Open Source Frameworks
Transcript
Open Source Frameworks
Open Source Frameworks Ingegneria del software (parte II) Andrea Bei 1 Framework Un framework è un insieme di classi e interfacce che cooperano e generalizzano task e workflow comuni di uno specifico dominio applicativo (funzionale o tecnologico) Un framework ha le seguenti caratteristiche Accelera la costruzione di applicazioni del dominio a cui si rivolge grazie al riuso della soluzione architetturale che ne costituisce la struttura I componenti del framework sono riusabili Utilizzo diffuso di classi astratte e interfacce Considerate come "template" per le sottoclassi o classi delle specifiche applicazioni. Adozione di un modello collaborativo Inversione del flusso di controllo (IOC) Lo sviluppatore non scrive codice per coordinare le componenti. Lo sviluppatore implementa le componenti che aderendo alla logica collaborativa del framework verranno coordinate da quest'ultimo. I framework assumono il controllo della applicazione e non il contrario! cfr ad esempio: pattern template method) 2 Framework Open Source Sono stati tra i principali elementi di innovazione nelle architetture web negli ultimi anni Hanno rappresentato il principale veicolo dell’esperienza “collettiva” degli sviluppatori in termini di design & architectural pattern, idioms, best practices Rispetto ai framework in-house (realizzati ad hoc) hanno una contribuzione di sviluppo più ampia e quindi una maggiore velocità di convergenza alla soluzione “migliore” per il dominio specifico Aumentano la produttività nello sviluppo Supportano la standardizzazione delle soluzioni Supportano un approccio allo sviluppo architettura-centrico Per uno sviluppatore/architetto Java EE la competenza su framework e librerie Open Source è fondamentale 3 Web Application Framework Un Web Application Framework è: un sistema software che fornisce struttura e comportamento generalizzati di task e workflow tipici delle applicazioni web. Es: gestione della navigazione (MVC), gestione dell’accesso ai dati (DAO), … Il framework di riferimento di IS/LIS (eUniversity) è un Web Application Framework didattico completo (nel senso che include tutti i task tipici di una applicazione web dalla presentazione all’accesso ai dati basandosi dai design pattern fondamentali) Nella “vita reale” per la realizzazione di web application è tipico l’utilizzo congiunto di diversi framework open source specializzati in aspetti specifici Ci concentreremo su alcuni di quelli più diffusi Struts / Struts 2 Spring Hibernate 4 Struts Struts E’ un insieme di classi ed interfacce che costituiscono l'infrastruttura per costruire web application Java EE conformi al design pattern Model 2 (MVC) Il suo ideatore è Craig McClanahan ed è stato donato alla Apache Software Foundation nel maggio del 2000 da parte di IBM. E’ uno dei web application framework più diffusi al mondo Struts 2 Nonostante il nome, Struts 2 non è una nuova release di Struts ma un framework completamente nuovo basato su WebWork Sono state introdotte caratteristiche non presenti in Struts grazie ai feedback di migliaia di sviluppatori 5 Spring Spring è un “lightweight” container che fornisce una soluzione per sviluppare applicazioni costruite su POJO. Si basa su: Inversion of Control/Dependency Injection (configurazione data-driven di POJO) AOP (Aspect Oriented Programming) ( Diverse componenti di utilità (tra cui una propria implementazione di MVC La prima versione venne scritta da Rod Johnson e rilasciata con la pubblicazione del proprio libro "Expert One-on-One Java EE Design and Development" (Wrox Press, Ottobre 2002). Spring è stato largamente riconosciuto all'interno della comunità Java quale valida alternativa al modello basato su Enterprise JavaBeans (EJB). Rispetto a quest'ultimo, il framework Spring lascia una maggiore libertà al programmatore fornendo allo stesso tempo un'ampia e ben documentata gamma di soluzioni 6 semplici adatte alle problematiche più comuni. Hibernate Hibernate (H8) è un middleware ORM (Object-relational mapping) open source. Consente la rappresentazione e la gestione su database relazionale di un sistema di oggetti Java. E’ stato originariamente sviluppato da un team internazionale di programmatori volontari coordinati da Gavin King; in seguito il progetto è stato proseguito sotto l'egida di JBoss, che ne ha curato la standardizzazione rispetto alle specifiche Java EE. 7 Mapping dei FW OS con eUniversity Struts (2) Hibernate Spring 8 Struts – class diagram 9 Struts – componenti principali Struts-config.xml fornisce alla ActionServlet, in base ai parametri della URL La Action da invocare La pagina JSP a cui inoltrare la richiesta ActionServlet: il controller di Model 2 Action: il Model di Model 2 (Classe base per le classi “action” ) Le classi action sono responsabili di Interfacciarsi con il layer sottostante (es: EJB, DAO, …) Recuperare i dati da presentare alla View e inserirli in sessione JSP: la View di Model 2 Le pagine JSP sono responsabili di Recuperare i dati da visualizzare dalla sessione Visualizzare i dati 10 Struts- esempio di struts-config <struts-config> <form-beans> <form-bean name=”projectForm” type=”it.uniroma2.app.form.ProjectListForm”/> </form-beans> <action-mappings> <action path=”/tasklist” type=” it.uniroma2.app.action.ProduceTaskListAction” name=”projectForm” scope=”request” validate=”true” input=”/jsp/Project.jsp”> <forward name=”success” path=”/jsp/TaskList.jsp”/> <forward name=”failure” path=”/jsp/ServerErrors.jsp”/> </action> </action-mappings> </struts-config> 11 Bibliografia Programming Jakarta Struts - Chuck Cavaness 12 Spring - Caratteristiche Spring è un lightweight container framework che supporta tecniche di IoC (inversion of control) e AoP (aspect-oriented programming) Lightweight (“leggero”) “leggero” per dimensione e overhead di elaborazione. (file JAR circa 1MB) Inversion of control Permette di sostenere “low coupling” (basso accoppiamento). Gli oggetti ricevono passivamente dall’esterno le loro dipendenze (es: il riferimento ad altri oggetti) , invece di crearle (new di oggeti) o cercarle in file esterni (es: classloading dinamico). Approccio “push” invece di “pull”. E’ il container che fornisce le dipendenze all’oggetto all’atto della istanziazione di quest’ultimo (Dependency Iniection) Aspect-oriented programming Permetta la SoC (separation of concern). Ovvero la separazione di responsabilità tra business logic e system services (come logging, autenticazione, gestione delle transazioni) 13 Spring - Caratteristiche Container Contiene e gestisce il ciclo di vita e la configurazione delle dipendenze degli oggetti. E’ possibile configurare come ogni singolo bean (POJO) deve essere creato (ad esempio in modalità “singleton”, pool, classica) e quali sono le sue dipendenze con gli altri bean. Framework Permette di configurare e comporre applicazioni complesse a partire da componenti più semplici in maniera dichiarativa (XML) Fornisce funzionalità infrastrutturali riusabili (transaction management, persistence framework integration, etc.), lasciando al developer solo lo sviluppo della logica di business 14 Spring Architettura 15 Spring Architettura Core container Contiene le funzionalità di base del framework. Contiene il BeanFactory, il “cuore” di ogni applicazione Spring-based, che che consiste in una implementazione del pattern factory che utilizza la tecnica IoC Modulo Application Context Contiene il supporto per l’internazionalizzazione (I18N messages), gestione degli eventi del ciclo di vita della applicazione, meccanismi di validazione, servizi come come e-mail, JNDI access, EJB integration, scheduling, integrazione con “templating framework” come Velocity e FreeMarker Modulo AOP E’ il componente base per lo sviluppo di aspects (le API sono conformi a quelle definite in AOP Alliance(*) . Permette la meta-programmazione. (è possibile aggiungere annotations per istruire Spring su dove e quando aggiungere aspetti) 16 Spring Architettura Modulo JDBC e DAO Aiuta a evitare il codice “boilerplate” proprio di JSBC (connessioni, resultset, …). Fornisce una astrazione del codice boilerplate e permette di semplificare il codice di accesso a db. Fornisce un layer di exception relative all’accesso al db “on top” rispetto a quelle native dei db. Modulo Web Context and Utility Si basa sul modulo Application Context e lo specializza per applicazioni. Fornisce il supporto a task web-oriented (es: file upload) e all’integrazione con Jakarta Struts . MVC framework Fornisce un framework Model/View/Controller (MVC) per la costruzione di web application. Spring’s MVC framework usa IoC per separare la logica di business e la logica di controllo e collegare in modo dichiarativo i parametri della request ai relativi oggetti di business (i.e. actions) Modulo O/R Mapping Punto di integrazione per Hibernate, JDO, OJB, iBATIS 17 Spring “hello world” public interface GreetingService { public void sayGreeting(); } public class GreetingServiceImpl implements GreetingService { private String greeting; public GreetingServiceImpl() {} public GreetingServiceImpl(String greeting) { this.greeting = greeting; } public void sayGreeting() { System.out.println(greeting); } public void setGreeting(String greeting) { this.greeting = greeting; } } GreetingServiceImpl GreetingServiceImplha haun unsolo soloattributo attributo(o (oproperty): property):greeting. greeting. La dellaclasse classepuò puòessere essereimpostata impostatatramite tramiteilil Laproperty propertyèèl’unica l’unicadipendenza dipendenzadella costruttore costruttoreootramite tramiteililmetodo metodosetter setter SPRING SPRINGIMPOSTA IMPOSTAIL ILVALORE VALOREDELLA DELLAPROPERTY PROPERTY Æ Æ 18 Spring “hello world” <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id=“greetingService” class="com.springinaction.chapter01.hello.GreetingServiceImpl"> <property name="greeting"> <value>Buenos Dias!</value> </property> </bean> </beans> TRAMITE TRAMITESETTER SETTER--EQUIVALE EQUIVALEAA GreetingServiceImpl GreetingServiceImplgreetingService greetingService==new newGreetingServiceImpl(); GreetingServiceImpl(); greetingService.setGreeting("Buenos Dias!"); greetingService.setGreeting("Buenos Dias!"); 19 Spring “hello world” <bean id="greetingService" class="com.springinaction.chapter01.hello.GreetingServiceImpl"> <constructor-arg> <value>Buenos Dias!</value> </constructor-arg> </bean> TRAMITE TRAMITECOSTRUTTORE COSTRUTTORE--EQUIVALE EQUIVALEAA GreetingServiceImpl GreetingServiceImplgreetingService greetingService==new newGreetingServiceImpl(“Buenos GreetingServiceImpl(“BuenosDias”); Dias”); 20 Spring “hello world” package com.springinaction.chapter01.hello; import java.io.FileInputStream; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; public class HelloApp { public static void main(String[] args) throws Exception { BeanFactory factory = new XmlBeanFactory(new FileInputStream("hello.xml")); GreetingService greetingService = (GreetingService) factory.getBean("greetingService"); greetingService.sayGreeting(); } } Risultato Risultato“Hello “HelloWorld”: World”:Come Comeconfigurare configurareun unbean beanmediante mediantel’injection l’injectiondidiuna una specifica stringa in una property. specifica stringa in una property. La Lareale realepotenzialià potenzialiàdidiSpring Springconsiste consistenel nelpoter poterfare farel’injection l’injectiondidiun unbean beanininun unaltro altro bean usando IoC Æ bean usando IoC Æ 21 IoC (Inversion of control) Hollywood Principle “Don’t call me, I’ll call you”. Lo sviluppatore implementa dei metodi che verranno chiamati dal framework E’ una tecnica usata nella progettazione dei framework Uno dei pattern per realizzarla è il Template Method (fig. a destra) Esempio: Servlet container Gestisce il ciclo di vita le request delle Servlet Invocando i metodi callback “Init”, “Destroy”, “doGet”, “doPost” abstract class AbstractClass { public void templateMethod() { // qui c’è l’algoritmo ... framework method1(); while (...) method2(); ... method3(); } abstract void method1(); abstract void method2(); abstract void method3(); } class ConcreteClass extends AbstractClass { void method1() {...} applicazione void method2() {...} void method3() {...} } 22 Dependency Iniection E’ un tipo particolare di inversione del controllo Tradizionalmente nell’ OOP ogni oggetto è responsabile di ottenere i riferimenti agli oggetti con cui collabora (le sue dipendenze) Applicando IoC, agli oggetti le dipendenze vengono fornite all’atto della creazione da un entità esterna che coordina ogni oggetto nel sistema. In altre parole le dipendenze vengono “iniettate” nell’oggetto In pratica in Spring il container inietta le dipendenze nell’oggetto tramite i suoi metodi Java usati come metodi callback (setter o costruttori). Le dipendenze possono essere oggetti, primitive (es: String) o tipi semplici (es: int, float) . DI è anche conosciuta come “push configuration”. Le dipendenze sono “spinte dentro” (push) l’oggetto dal container piuttosto che “prelevate” (pull) dall’oggetto stesso PULL PUSH Dependency DependencyInjection InjectionPattern Pattern 23 DI Esempio public public class class KnightOfTheRoundTable KnightOfTheRoundTable {{ private private String String name; name; private HolyGrailQuest private HolyGrailQuest quest; quest; public public KnightOfTheRoundTable(String KnightOfTheRoundTable(String name) name) {{ this.name this.name == name; name; quest = new HolyGrailQuest(); quest = new HolyGrailQuest();-> L’oggetto recupera la propria dipendenza }} public public HolyGrail HolyGrail embarkOnQuest() embarkOnQuest() throws throws GrailNotFoundException GrailNotFoundException {{ return return quest.embark(); quest.embark(); }} }} public public class class HolyGrailQuest HolyGrailQuest {{ public public HolyGrailQuest() HolyGrailQuest() {} {} public public HolyGrail HolyGrail embark() embark() throws throws GrailNotFoundException GrailNotFoundException {{ HolyGrail HolyGrail grail grail == null; null; // // Look Look for for grail grail …… return return grail; grail; }} }} 24 DI Esempio import import junit.framework.TestCase; junit.framework.TestCase; public class public class KnightOfTheRoundTableTest KnightOfTheRoundTableTest extends extends TestCase TestCase {{ public public void void testEmbarkOnQuest() testEmbarkOnQuest() {{ KnightOfTheRoundTable KnightOfTheRoundTable knight knight == new new KnightOfTheRoundTable("Bedivere"); KnightOfTheRoundTable("Bedivere"); try try {{ HolyGrail HolyGrail grail grail == knight.embarkOnQuest(); knight.embarkOnQuest(); assertNotNull(grail); assertNotNull(grail); assertTrue(grail.isHoly()); assertTrue(grail.isHoly()); }} catch catch (GrailNotFoundException (GrailNotFoundException e) e) {{ fail(); fail(); }}} }}} Se Sesisiesegue esegueililtest testsu suKnightOfTheRoundTable, KnightOfTheRoundTable,indirettamente indirettamentesisieffettua effettuaililtest test anche su HolyGrailQuest anche su HolyGrailQuest Inoltre Inoltreèèimpossibile impossibileavere avereun uncomportamento comportamentodiverso diversoHolyGrailQuest HolyGrailQuest(e.g., (e.g.,return return null o throw GrailNotFoundException) per diversi test null o throw GrailNotFoundException) per diversi test Se Sesisista stautilizzando utilizzandoper perHolyGrailQuest HolyGrailQuestun unmock mockobject objectper persimulare simulareun unoggetto oggettoreale reale ininambiente di test si deve modificare il codice per farlo funzionare in ambiente di ambiente di test si deve modificare il codice per farlo funzionare in ambiente di produzione produzione 25 DI Esempio Il problema è l’accoppiamento. KnightOfTheRoundTable è staticamente accoppiato con HolyGrailQuest (non si può avere un KnightOfTheRoundTable senza avere anche un HolyGrailQuest) L’accoppiamento è necessario ma va minimizzato Necessario: Due oggetti sono accoppiati quando uno dipende dall’altro, ma un programma OO in esecuzione è proprio un insieme di oggetti che dipendono l’uno dall’altro (eseguono dei compiti o delegano l’esecuzione ad altri oggetti dipendenti) Minimizzato: Va reso più basso possibile perchè riduce la leggibilità, manutenibilità, testabilità (pattern GRASP “low coupling”). Un modo per ridurre l’accoppiamento diretto è introdurre un livello di indirezione mediante interfacce public public interface interface Quest Quest {{ public public abstract abstract Object Object embark() embark() throws throws QuestException; QuestException; }} public public class class HolyGrailQuest HolyGrailQuest implements implements Quest Quest {{ public public HolyGrailQuest() HolyGrailQuest() {} {} public public Object Object embark() embark() throws throws QuestException QuestException {{ // // Do Do whatever whatever it it means means to to embark embark on on aa quest quest return new HolyGrail(); return new HolyGrail(); }} }} private private Quest Quest quest; quest; …… public public Object Object embarkOnQuest() embarkOnQuest() throws throws QuestException { QuestException { return return quest.embark(); quest.embark(); }} Nella classe KnightOfTheRoundTable uso il tipo interfaccia 26 DI Esempio public public interface interface Knight Knight {{ public public Object Object embarkOnQuest() embarkOnQuest() throws throws QuestException; QuestException; }} public public class class KnightOfTheRoundTable KnightOfTheRoundTable implements implements Knight Knight {{ private private Quest Quest quest; quest; …… public public KnightOfTheRoundTable(String KnightOfTheRoundTable(String name) name) {{ quest quest == new new HolyGrailQuest(); HolyGrailQuest(); …… }} public public Object Object embarkOnQuest() embarkOnQuest() throws throws QuestException QuestException {{ return return quest.embark(); quest.embark(); }} }} Anche Anchecon conleleinterfacce interfaccenon nonrisolvo risolvoililproblema problemaperchè perchèun unKnightOfTheRoundTable KnightOfTheRoundTableisisvincolato vincolato solo ad un tipo di ricerca per “Holy Grail” e nessun altro tipo di ricerca solo ad un tipo di ricerca per “Holy Grail” e nessun altro tipo di ricerca 27 DI Esempio E’E’giusto giustoche cheililcavaliere cavalierescelga scelgada dasolo sololalapropria propriaricerca ricerca(missione) (missione)ooèèpiù più conveniente/utile che gli venga assegnata ? conveniente/utile che gli venga assegnata ? public public class class KnightOfTheRoundTable KnightOfTheRoundTable implements implements Knight Knight {{ private private Quest Quest quest; quest; …… public public KnightOfTheRoundTable(String KnightOfTheRoundTable(String name) name) {{ …… }} public public HolyGrail HolyGrail embarkOnQuest() embarkOnQuest() throws throws QuestException QuestException {{ …… return return quest.embark(); quest.embark(); }} public public void void setQuest(Quest setQuest(Quest quest) quest) {{ this.quest this.quest == quest; quest; }} }} Ora OraKnightOfTheRoundTable KnightOfTheRoundTablenon nonèèpiù piùresponsabile responsabiledidirecuperare recuperareleleproprie propriemissioni. missioni. Inoltre poiché KnightOfTheRoundTable è dipendente solo dall’interfaccia Quest Inoltre poiché KnightOfTheRoundTable è dipendente solo dall’interfaccia Questèèpossibile possibile passargli qualsiasi implementazione di tale interfaccia. passargli qualsiasi implementazione di tale interfaccia. La Laresponsabilità responsabilitàdidicoordinare coordinarelalacollaborazione collaborazionetra traoggetti oggettidipendenti dipendentièèscorporata scorporatadagli dagli oggetti stessi. oggetti stessi. es: In ambiente di produzione potremmo aver bisogno di un tipo di HolyGrailQuest, 28ma es: In ambiente di produzione potremmo aver bisogno di un tipo di HolyGrailQuest, ma ininambiente di test potremmo avere una implementazione mock (mock object) ambiente di test potremmo avere una implementazione mock (mock object) DI Esempio Ora Orache chel’oggetto l’oggettoèèpronto prontoaaricevere riceveredall’”esterno” dall’”esterno”una una dipendenza chi la passa ? QUI ENTRA IN GIOCO SPRING dipendenza chi la passa ? QUI ENTRA IN GIOCO SPRING L’azione L’azionedidicreare creareassociazioni associazionitra tracomponenti componentiapplicativi applicativi èèdetta wiring (cablare/collegare fili elettrici). In detta wiring (cablare/collegare fili elettrici). InSpring, Spring, cicisono molti modi di collegare tra loro componenti sono molti modi di collegare tra loro componenti ma ma ililpiù comune è tramite XML (“knight.xml”) più comune è tramite XML (“knight.xml”) <?xml <?xml version="1.0" version="1.0" encoding="UTF-8"?> encoding="UTF-8"?> <!DOCTYPE beans PUBLIC <!DOCTYPE beans PUBLIC "-//SPRING//DTD "-//SPRING//DTD BEAN//EN" BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <beans> <bean <bean id="quest“ id="quest“ class="com.springinaction.chapter01.knight.HolyGrailQuest"/> class="com.springinaction.chapter01.knight.HolyGrailQuest"/> <bean id="knight“ <bean id="knight“ class="com.springinaction.chapter01.knight.KnightOfTheRoundTable"> class="com.springinaction.chapter01.knight.KnightOfTheRoundTable"> <constructor-arg> <constructor-arg> <value>Bedivere</value> <value>Bedivere</value> </constructor-arg> </constructor-arg> <property <property name="quest"> name="quest"> <ref <ref bean="quest"/> bean="quest"/> </property> </property> </bean> </bean> </beans> </beans> 29 DI Esempio import import org.springframework.beans.factory.BeanFactory; org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; public public class class KnightApp KnightApp {{ public public static static void void main(String[] main(String[] args) args) throws throws Exception Exception {{ BeanFactory BeanFactory factory factory == new new XmlBeanFactory(new XmlBeanFactory(new FileInputStream("knight.xml")); FileInputStream("knight.xml")); KnightOfTheRoundTable knight = (KnightOfTheRoundTable)factory.getBean("knight"); KnightOfTheRoundTable knight = (KnightOfTheRoundTable)factory.getBean("knight"); knight.embarkOnQuest(); knight.embarkOnQuest(); }} }} 30 Aspect Oriented Programming (AOP) E’ un paradigma per incapsulare il codice “crosscutting” Il codice che altrimenti sarebbe disperso (sparso) tra oggetti e metodi (es: )può essere raggruppato in un solo punto logging, security, transaction Codice “disperso” Layers Per Perintuire intuireililfunzionamento funzionamentosisipensi pensialalconcetti concettididiInterceptor Interceptor(e.g. (e.g.interceptor interceptordidi Struts2) Struts2) Il client invoca un proxy Il client invoca un proxy Una catena di interceptors (layer) decora le successive chiamate fino al metodo Una catena di interceptors (layer) decora le successive chiamate fino al metodo target target Gli interceptor forniscono servizi come transaction management, logging, security Gli interceptor forniscono servizi come transaction management, logging, security I servizi sono specificati dichiarativamente I servizi sono specificati dichiarativamente 31 Esempio di AOP package com.springinaction.chapter01.knight; import org.apache.log4j.Logger; public class Minstrel { Logger song = Logger.getLogger(KnightOfTheRoundTable.class); public Minstrel() {} public void compose(String name, String message) { song.debug("Fa la la! Brave " + name + " did " + message + "!"); }} public class KnightOfTheRoundTable { … private Minstrel minstrel; public void setMinstrel(Minstrel minstrel) { this.minstrel = minstrel; } … public HolyGrail embarkOnQuest() throws QuestException { minstrel.compose(name, "embark on a quest"); return quest.embark(); Ideally a minstrel (metafora di un logger) would automatically compose songs } without being explicitly told to do so } 32 Esempio di AOP package com.springinaction.chapter01.knight; import java.lang.reflect.Method; import org.apache.log4j.Logger; import org.springframework.aop.MethodBeforeAdvice; public class MinstrelAdvice implements MethodBeforeAdvice { public MinstrelAdvice() {} public void before(Method method, Object[] args,Object target) throws Throwable { Knight knight = (Knight) target; Logger song = Logger.getLogger(target.getClass()); song.debug("Brave " + knight.getName() +" did " + method.getName()); } } Applying advice to an object is known as weaving 33 Bibliografia Spring in action - Craig Walls Ryan Breidenbach – Manning 34 Hibernate - Caratteristiche Hibernate è un middleware ORM (Object Relational Mapping). La funzione principale di un ORM è l’automatica e trasparente persistenza di oggetti nelle tabelle di un DB relazionale tramite metadata che descrivono il mapping tra oggetti e entità del DB. Lo strato ORM trasforma dati da una rappresentazione e l’altra in entrambi i versi Ogni middleware ORM comprende i seguenti elementi: API per eseguire operazioni CRUD (Create Read Update Delete) su oggetti di classi persistenti Un linguaggio o API per specificare delle Query su classi e proprietà di classi Una “facility” per specificare i mapping metadata Una tecnica per gestire oggetti transazionali per eseguire dirty checking, lazy association fetching, ed altre funzioni di ottimizzazione 35 Hibernate “Hello World” package package hello; hello; public class Message { public class Message { private private Long Long id; id; private String private String text; text; private Message private Message nextMessage; nextMessage; private Message() private Message() {} {} public Message(String public Message(String text) text) {{ this.text this.text == text; text; }} public public Long Long getId() getId() {{ return return id; id; }} private private void void setId(Long setId(Long id) id) {{ this.id this.id == id; id; }} public public String String getText() getText() {{ return return text; text; }} Applying advice to an object is known as weaving public public void void setText(String setText(String text) text) {{ this.text this.text == text; text; }} public public Message Message getNextMessage() getNextMessage() {{ return return nextMessage; nextMessage; }} public public void void setNextMessage(Message setNextMessage(Message nextMessage) nextMessage) {{ this.nextMessage this.nextMessage == nextMessage; nextMessage; }} }} 36 Hibernate “Hello World” Session Session session session == getSessionFactory().openSession(); getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); Transaction tx = session.beginTransaction(); Message Message message message == new new Message("Hello Message("Hello World"); World"); session.save(message); session.save(message); tx.commit(); tx.commit(); session.close(); session.close(); equivale a insert insert into into MESSAGES MESSAGES (MESSAGE_ID, (MESSAGE_ID, MESSAGE_TEXT, MESSAGE_TEXT, NEXT_MESSAGE_ID) NEXT_MESSAGE_ID) values (1, 'Hello World', null) values (1, 'Hello World', null) 37 Hibernate “Hello World” Session Session newSession newSession == getSessionFactory().openSession(); getSessionFactory().openSession(); Transaction newTransaction Transaction newTransaction == newSession.beginTransaction(); newSession.beginTransaction(); List from List messages messages == newSession.find(" newSession.find(" from Message Message as as mm order order System.out.println( messages.size() + " message(s) found:" System.out.println( messages.size() + " message(s) found:" ); ); for ( Iterator iter = messages.iterator(); iter.hasNext(); ) for ( Iterator iter = messages.iterator(); iter.hasNext(); ) {{ Message Message message message == (Message) (Message) iter.next(); iter.next(); System.out.println( message.getText() System.out.println( message.getText() ); ); }} newTransaction.commit(); newTransaction.commit(); newSession.close(); newSession.close(); by by m.text m.text asc asc"); "); Hibernate Query Language (HQL) equivale a select select m.MESSAGE_ID, m.MESSAGE_ID, m.MESSAGE_TEXT, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID m.NEXT_MESSAGE_ID from MESSAGES m from MESSAGES m order order by by m.MESSAGE_TEXT m.MESSAGE_TEXT asc asc 38 Hibernate “Hello World” XML Mapping <?xml <?xml version="1.0"?> version="1.0"?> <!DOCTYPE <!DOCTYPE hibernate-mapping hibernate-mapping PUBLIC PUBLIC "-//Hibernate/Hibernate Mapping "-//Hibernate/Hibernate Mapping DTD//EN" DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <hibernate-mapping> <class <class name="hello.Message“ name="hello.Message“ table="MESSAGES"> table="MESSAGES"> <id name="id“ column="MESSAGE_ID"> <id name="id“ column="MESSAGE_ID"> <generator <generator class="increment"/> class="increment"/> </id> </id> <property <property name="text“ name="text“ column="MESSAGE_TEXT"/> column="MESSAGE_TEXT"/> <many-to-one name="nextMessage“ <many-to-one name="nextMessage“ cascade="all“ cascade="all“ column="NEXT_MESSAGE_ID"/> column="NEXT_MESSAGE_ID"/> </class> </class> </hibernate-mapping> </hibernate-mapping> 39 Hibernate “Hello World” Session Session session session == getSessionFactory().openSession(); getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); Transaction tx = session.beginTransaction(); // // 11 is is the the generated generated id id of of the the first first message message Message message = (Message) session.load( Message message = (Message) session.load( Message.class, Message.class, new new Long(1) Long(1) ); ); message.setText("Greetings Earthling"); message.setText("Greetings Earthling"); Message Message nextMessage nextMessage == new new Message("Take Message("Take me me to to your your leader leader (please)"); (please)"); message.setNextMessage( nextMessage ); message.setNextMessage( nextMessage ); tx.commit(); tx.commit(); session.close(); session.close(); equivale a select select m.MESSAGE_ID, m.MESSAGE_ID, m.MESSAGE_TEXT, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID m.NEXT_MESSAGE_ID from MESSAGES m from MESSAGES m where where m.MESSAGE_ID m.MESSAGE_ID == 11 insert insert into into MESSAGES MESSAGES (MESSAGE_ID, (MESSAGE_ID, MESSAGE_TEXT, MESSAGE_TEXT, NEXT_MESSAGE_ID) NEXT_MESSAGE_ID) values (2, 'Take me to your leader (please)', null) values (2, 'Take me to your leader (please)', null) update MESSAGES update MESSAGES set set MESSAGE_TEXT MESSAGE_TEXT == 'Greetings 'Greetings Earthling', Earthling', NEXT_MESSAGE_ID NEXT_MESSAGE_ID == 22 where where MESSAGE_ID MESSAGE_ID == 11 40 Hibernate Architettura 4 Tipi di API Interfacce chiamate dall’applicazione per eseguire operazioni CRUD e Query (Session, Transaction, and Query) Interfacce chiamate per configurare hibernate (la principale è Hibernate) la principale è la classe Configuration Interfacce Callback che permettono alla applicazione di reagire automaticamente ad eventi interni ad Hibernate (Interceptor, Lifecycle, Validatable= Interfacce che permettono l’estensione delle funzionalità di mapping di 41 Hibernate ( UserType, CompositeUserType, IdentifierGenerator) Hibernate Architettura Interfaccia Session Il concetto di Session Hibernate si pone tra quello di connection e transaction. Una session è una “cache” di oggetti caricati relativamente ad una unità di lavoro Interfaccia SessionFactory L’applicazione ottiene una istanza di Session da un SessionFactory. Esiste una SessionFactory per ogni database La SessionFactory esegue il caching di istruzioni SQL e metadati Interfaccia Configuration L’oggetto Configuration è usato per configurare Hibernate. L’applicazione usa una istanza di Configuration per recuperare la posizione dei documenti di mapping e delle proprietà e successivamente crea la SessionFactory Interfaccia Transaction E’ opzionale: si può decidere di gestire le transazioni ad hoc nel proprio codice. Una interfaccia Transaction astrae l’applicazione dal particolare tipo di tecnologia usata per le transazioni: JDBC, JTA UserTransaction, o CORBA transaction Interfacce Query e Criteria L’interfaccia Query permette di eseguire query. Le query possono essere scritte in HQL o nel dialetto SQL del DB di riferimento. L’oggetto Query è usato per effettuare il bind dei parametri della query, limitare il numero dei risultati ritornati dalla query ed eseguire la query. L’interfaccia Criteria è simile; permette di creare ed eseguire query objectoriented 42 Managed Env VS Non Managed Env Managed Environment Resource Pool (es: db connection), Transazionalità e Sicurezza sono gestiti in modo dichiarativo Application Server come Jboss; Glassfish; WebSphere; WebLogic forniscono un managed environment Non Managed Environment Fornisce semplicemente la gestione delle richieste concorrenti (Servlet Container come TomCat) Per le connessioni si utilizza JDBC e Transazionalità e Sicurezza sono sviluppati nell’applicazione Hibernate può essere usato in entrambi gli ambienti Nel seguito ci si riferisce al Non Managed Environment 43 Hibernate Startup Startup di Hibernate Localizzare il file di mapping tramite l’oggetto Configuration Creare un SessionFactory Regole 1. Il file di mapping (Message.hbm.xml) deve essere visibile nel CLASSPATH 2. Per convenzione 1 map file per classe (è possibile invocare più volte il metodo addResource per caricarli tutti) 3. Per impostare le configurazioni 3 alternativa java -Dproperty=value. file hibernate.properties nel classpath. Tag <property> in hibernate.cfg.xml nel classpath. Equivalente Equivalentecon conililmethod methodchaining chaining Configuration Configuration cfg cfg == new new Configuration(); Configuration(); cfg.addResource("hello/Message.hbm.xml"); cfg.addResource("hello/Message.hbm.xml"); cfg.setProperties( cfg.setProperties( System.getProperties() System.getProperties() ); ); SessionFactory sessions = cfg.buildSessionFactory(); SessionFactory sessions = cfg.buildSessionFactory(); Configuration Configuration cfg cfg == new new Configuration() Configuration() .addResource("hello/Message.hbm.xml") .addResource("hello/Message.hbm.xml") .setProperties(System.getProperties()) .setProperties(System.getProperties()) .buildSessionFactory(); .buildSessionFactory(); 44 Connection Pool Supporto al connection pool open source C3P0 (altri supportati sono Apache DBCP e Proxool) Senza SenzaHibernate Hibernate Con ConHibernate Hibernate File File hibernate.properties hibernate.properties hibernate.connection.driver_class hibernate.connection.driver_class == org.postgresql.Driver org.postgresql.Driver hibernate.connection.url = jdbc:postgresql://localhost/auctiondb hibernate.connection.url = jdbc:postgresql://localhost/auctiondb hibernate.connection.username hibernate.connection.username == auctionuser auctionuser hibernate.connection.password = secret hibernate.connection.password = secret hibernate.dialect hibernate.dialect == net.sf.hibernate.dialect.PostgreSQLDialect net.sf.hibernate.dialect.PostgreSQLDialect hibernate.c3p0.min_size=5 hibernate.c3p0.min_size=5 hibernate.c3p0.max_size=20 hibernate.c3p0.max_size=20 hibernate.c3p0.timeout=300 hibernate.c3p0.timeout=300 hibernate.c3p0.max_statements=50 hibernate.c3p0.max_statements=50 hibernate.c3p0.idle_test_period=3000 hibernate.c3p0.idle_test_period=3000 45 Caso di Studio: Modello di Dominio-Aste Online 1° 1°Passo: Passo: Disegnare DisegnareililModello ModellodidiDominio Dominio 46 Caso di Studio: Modello di Dominio-Aste Online 2° 2°Passo: Passo: Progettare Progettarei iPOJO POJO(o(oJavaBean) JavaBean) public public class class User User implements implements Serializable Serializable {{ private private String String username; username; private Address private Address address; address; public User() {} public User() {} public public String String getUsername() getUsername() {{ return return username; username; }} public public void void setUsername(String setUsername(String username) username) {{ this.username this.username == username; username; }} public public Address Address getAddress() getAddress() {{ return return address; address; }} public public void void setAddress(Address setAddress(Address address) address) {{ this.address this.address == address; address; }} public public MonetaryAmount MonetaryAmount calcShippingCosts(Address calcShippingCosts(Address fromLocation) { fromLocation) { ... ... }} }} Impl. Impl.Serializable Serializable Setter/Getter Setter/Getter Business BusinessMethod Method 47 Caso di Studio: Modello di Dominio-Aste Online 3° 3°Passo: Passo: Progettare Progettareleleassociazioni associazioni public public class class Category Category implements implements Serializable Serializable {{ private private String String name; name; private Category private Category parentCategory; parentCategory; private Set childCategories private Set childCategories == new new HashSet(); HashSet(); public Category() { } public Category() { } ... ... public public void void setName(String setName(String name) name) {{ this.name this.name == name; name; }} public public Set Set getChildCategories() getChildCategories() {{ Codice return Codice“Scaffolding” “Scaffolding” return childCategories; childCategories; }} public public void void setChildCategories(Set setChildCategories(Set childCategories) childCategories) {{ this.childCategories this.childCategories == childCategories; childCategories; }} public public Category Category getParentCategory() getParentCategory() {{ return return parentCategory; parentCategory; }} public public void void setParentCategory(Category setParentCategory(Category parentCategory) parentCategory) {{ this.parentCategory this.parentCategory == parentCategory; parentCategory; }} }} 48 Caso di Studio: Modello di Dominio-Aste Online 3° 3°Passo: Passo: Progettare Progettareleleassociazioni associazioni(…aggiungere (…aggiungereelementi) elementi) Category Category aParent aParent == new new Category(); Category(); Category aChild = new Category(); Category aChild = new Category(); aChild.setParentCategory(aParent); aChild.setParentCategory(aParent); aParent.getChildCategories().add(aChild); aParent.getChildCategories().add(aChild); Codice Codice“Scaffolding” “Scaffolding” 3° 3°Passo: Passo: Progettare Progettareassociazioni associazioni public public class class Category Category {{ ... ... private private Set Set items items == new new HashSet(); HashSet(); ... ... public public Set Set getItems() getItems() {{ return return items; items; }} public public void void setItems(Set setItems(Set items) items) {{ this.items this.items == items; items; }} }} Codice Codice“Scaffolding” “Scaffolding” Categoria Categoria>>Item Item 49 Caso di Studio: Modello di Dominio-Aste Online 3° 3°Passo: Passo: Progettare Progettareleleassociazioni associazioni public public class class Item Item {{ private private String String name; name; private String description; private String description; ... ... private private Set Set categories categories == new new HashSet(); HashSet(); ... ... public public Set Set getCategories() getCategories() {{ Codice Codice“Scaffolding” “Scaffolding” return categories; return categories; Item > Categoria Item > Categoria }} private private void void setCategories(Set setCategories(Set categories) categories) {{ this.categories this.categories == categories; categories; }} public public void void addCategory(Category addCategory(Category category) category) {{ if if (category (category == == null) null) throw new IllegalArgumentException("Null throw new IllegalArgumentException("Null category"); category"); category.getItems().add(this); category.getItems().add(this); categories.add(category);}} categories.add(category);}} 50 Caso di Studio: Modello di Dominio-Aste Online 4° 4°Passo: Passo: Definire Definirei imetadata metadata <?xml <?xml version="1.0"?> version="1.0"?> <!DOCTYPE <!DOCTYPE hibernate-mapping hibernate-mapping PUBLIC "-//Hibernate/Hibernate PUBLIC "-//Hibernate/Hibernate Mapping Mapping DTD//EN" DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <hibernate-mapping> <class <class name="org.hibernate.auction.model.Category“ name="org.hibernate.auction.model.Category“ table="CATEGORY"> table="CATEGORY"> <id name="id“ column="CATEGORY_ID“ type="long"> <id name="id“ column="CATEGORY_ID“ type="long"> <generator <generator class="native"/> class="native"/> </id> </id> <property <property name="name“ name="name“ column="NAME“ column="NAME“ type="string"/> type="string"/> </class> </class> </hibernate-mapping> </hibernate-mapping> 51 Bibliografia Hibernate in Action - CHRISTIAN BAUER-GAVIN KING Manning 52