Università degli Studi di Salerno Programmazione su Reti 2 Relazione: Enterprise Java Beans e Web Services Prof. Auletta Vincenzo Enterprise Java Beans e Web Services Data:20/05/2005 Partecipanti Antonio Autorino 156/000006 Nicola Vitiello 156/000001 Pasquale Paola 156/000003 Indice degli argomenti 1. Introduzione 3 2. J2EE 2.1 Sistemi Distribuiti ad oggetti 2.1.1 Oggetti distribuiti 2.1.2 Oggetti distribuiti con middleware esplicito 2.1.3 Oggetti distribuiti con middleware implicito 2.2 J2EE : overview 2.2.1 J2EE: il container 4 4 5 6 7 8 8 3. Enterprise Java Bean 3.1 La classificazione 3.1.1 Architettura di un applicazione distribuita 3.2 Session Bean 3.2.1 Implementazione di un Session Bean 10 10 11 11 13 4. Gli Entity Bean 17 5. JMS 5.1 23 25 25 EJB e Web Services 6.1 Esportare gli EJB tramite web services 6.1.1 Soluzioni proprietarie degli EJB container 6.1.2 Utilizzare un motore SOAP esterno all’EJB container 6.2 Esempio: HelloBean 6.3 Esempio: Skatestown 6.3.1 Entity CMP: Product 6.3.2 Session Stateless: SkatesProducts 26 26 26 26 27 30 30 34 MDB 6. Programmazione su Reti 2 2004/2005 Pagina 2 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 1. Introduzione Questa relazione presenta due delle più importanti tecnologie del settore dei sistemi distribuiti ad oggetti: Enterprise Java Beans e i Web Services . Dopo una breve panoramica sulle tecnologie utilizzate per la realizzazione dei sistemi distribuiti e sulla piattaforma J2EE progettata dalla SUN per la realizzazione di applicazioni distribuite in JAVA, il seguente documento si concentra sulla descrizione degli Enterprise Java Beans, la loro classificazione, il loro ciclo di vita, la loro implementazione e il loro deployment. Nell’ultima sezione della relazione viene presentata la possibilità di utilizzare gli EJB come dei Web Services, vengono analizzate tre possibili soluzioni per implementare tale scenario e sarà fornito un esempio dettagliato sull’utilizzo degli EJB, in cui AXIS funge da processore SOAP lato Client e Server per la comunicazione tra le due applicazioni. Grazie alla combinazione di AXIS e J2EE è possibile ottenere l’implementazione di un sistema distribuito che può basare : • la robustezza, la sicurezza, l’affidabilità, la gestione delle transazioni e la persistenza delle informazioni, la gestione delle risorse in generale, baandosi esclusivamnte sui servizi offerti dalla piattaforma J2EE. • l’interoperabilità tra l’applicazione lato server e una specifica applicazione lato client (realizzata in qualsiasi linguaggio di programmazione) grazie all’utilizzo dei Web Services. Bisogna infatti sottolineare che J2EE è un infrastruttura affidabile, sicura e di alta qualità, utilizzata per la realizzazione di complesse applicazioni distribuite di business. L’unico limite di questo ambiente era legato al fatto che l’implementazione di un meccanismo di comunicazione tra un Client C/C++/C# e un applicazione Server-Side su J2EE era molto complesso da realizzare . Grazie alla nascita dei Web Services e del protocollo SOAP è possibile interfacciare queste applicazioni di business Server-Side con qualsiasi Client . Allo stesso tempo è possibile implementare Web Services tramite EJB senza utilizzare una piattaforma troppo limitata nei servizi di middleware offerti (come il connubio Application Server Tomcat e Axis) ma utilizzando una piattaforma più robusta e completa, quale J2EE. Rimane il fatto che la modalità di implementazione dei Web Services classica, che è stata illustrata durante il corso, può essere comunque utilizzata, specialmente quando lo scenario prevede semplici funzionalità e requisiti non funzionali non troppo pressanti da rispettare. Programmazione su Reti 2 2004/2005 Pagina 3 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 2. J2EE J2EE è una piattaforma utilizzata per realizzare applicazioni distribuite in Java. Standardizza modelli di programmazione e modelli di deployment allo scopo di fornire gli strumenti necessari ad uno sviluppatore per implementare soluzioni veloci alla realizzazione di sistemi distribuiti ad oggetti. Per comprendere tutte le caratteristiche di J2EE dobbiamo descrivere inizialmente cos’è un sistema distribuito e cosa intendiamo per sistemi distribuiti ad oggetti . 2.1 Sistemi Distribuiti ad oggetti I sistemi distribuiti offrono una maggiore accessibilità ai servizi offerti ; infatti parte del sistema può essere ubicata in locazioni diverse e lo stesso accesso al sistema può avvenire da locazioni diverse. Tra le piattaforme software più utilizzate per la realizzazione di sistemi distribuiti possiamo citare Java RMI, CORBA, DCOM, etc; queste offrono la possibilità di avere oggetti che vengono eseguiti su una macchina ed utilizzati da altre applicazioni (oggetti) su un’altra macchina. Il modello che seguiamo per la realizzazione di sistemi distribuiti è descritto nella figura 2.1 Figura 2.1 Il modello presentato prende il nome di Modello 3 Tier e come è possibile osservare ,abbiamo un sistema distribuito strutturato in tre livelli: • Livello 1 Presentazione : è caratterizzato da i nodi del sistema in cui vi è l’accesso degli utenti e in cui girano le applicazioni Client . Programmazione su Reti 2 2004/2005 Pagina 4 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 • Livello 2 Logica di business : è caratterizzato dalla presenza dell’applicazione software lato server che implementa l’intera logica di business : operazioni ,servizi,calcoli etc… • Livello 3 Logica dei Dati: è il tipico Data Layer di un ‘applicazione ; può risiedere sulla stessa macchina dell’applicazione di business o su un altro insieme di nodi remoti. In questa relazione facciamo riferimento principalmente al livello 2/3 quando parleremo di Entity Bean e al livello 2 quando tratteremo i Session Bean Il passaggio da sistemi distribuiti a sistemi distribuiti ad oggetti consiste nella sostituzione delle applicazioni tipiche della logica di business ,scritte per esempio in Cobol o C,con oggetti distribuiti. L’ incapsulazione della logica di business in oggetti permette di ottenere software FER(Flessibile Estendibile e Riutilizzabile), che è uno degli obiettivi del paradigma di programmazione object–oriented. Definizione: un modello di componenti server-side definisce una architettura per lo sviluppo di oggetti di business distribuiti. Quindi cosa sono le componenti server-side? In poche parole le componenti server-side sono gli oggetti distribuiti finora citati. Sono usate negli application server (per esempio TomCat o l’application Server di J2EE),che gestiscono le componenti a run-time e permettono il loro assemblaggio. Sono “pezzi indipendenti” di software e possono essere acquistate, vendute e composte come tali. Un sistema di business basato su componenti server-side è: o fluido perché è costituito da oggetti o accessibile • perché le componenti possono essere distribuite 2.1.1 Oggetti distribuiti Il modello più semplice che viene utilizzato per la descrizione e l’implementazione dei sistemi distribuiti è il modello ad Oggetti Distribuiti. Tra le tecnologie che implementano tal modello possiamo citare : Sun Java RMI, CORBA, MS DCOM. Programmazione su Reti 2 2004/2005 Pagina 5 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 Figura 2.2 La figura 2.2 rappresenta graficamente il modello : • lo Stub o rappresenta il proxy del Server lato Client ,cioè offre in locale all’applicazione Client gli stessi metodi del Server . o Affinché avvenga ciò, lo Stub implementa un interfaccia remota che l’applicazione Client deve assolutamente conoscere per invocare i metodi sullo Stub o Nasconde i dettagli della comunicazione sulla rete all’applicazione Client. • Lo Skeleton o Riceve i dati dalla rete inviati dallo stub (il nome della funzionalità da invocare e i parametri necessari) o Invoca il metodo sull’oggetto remoto che implementa anch’esso l’interfaccia remota. o Restituisce il risultato allo Stub. Lo stub e lo skeleton rappresentano il middleware di tale sistema distribuito. 2.1.2 Oggetti distribuiti con middleware esplicito Il modello ad Oggetti Distribuiti con Middleware esplicito è leggermente diverso dal precedente modello perché l’oggetto remoto/server accede tramite delle specifiche API ,offerte dallo strato software middleware, a servizi utili, relativi per esempio alla gestione del database o alla gestione della sicurezza etc . Tra le tecnologie che implementano tale modello possiamo citare CORBA. La figura 2.3 rappresenta graficamente il modello. Programmazione su Reti 2 2004/2005 Pagina 6 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 Figura 2.3 2.1.3 Oggetti distribuiti con middleware implicito Il modello ad Oggetti Distribuiti con Middleware implicito è sostanzialmente diverso dai due precedenti modelli perché nella interazione Skeleton – Oggetto distribuito si interpone il Request Interceptor ; quest’oggetto è parte integrante del middleware ed è configurato in fase di deployment della componente server-side affinché fornisca automaticamente i servizi necessari (per esempio la gestione del database o la gestione della sicurezza etc) . Tra le tecnologie che implementano tal modello possiamo citare EJB, CORBA Component Model, .NET La figura 2.4 rappresenta graficamente il modello. Figura 2.4 Programmazione su Reti 2 2004/2005 Pagina 7 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 2.2 J2EE : overview Adesso possiamo descrivere le caratteristiche della piattaforma J2EE in modo esaustivo, dopo aver trattato degli argomenti chiave relativi ai sistemi distribuiti a d oggetti. J2EE sta a significare Java 2 Enterprise Edition e come abbiamo detto, è una piattaforma utilizzata per realizzare applicazioni distribuite in Java. I modelli di applicazioni distribuiti più utilizzati e supportati dall’ambiente J2EE sono: • Applicazioni browser-based ,in cui il lato server è implementato con JSP e Servlets • Applicazioni basate sull’utilizzo di RMI-IIOP per la comunicazione tra Client e EJB lato Server • Applicazioni basate sullo scambio di messaggi utilizzando JMS • Applicazioni service-based che tramite SOAP/HTTP offrono servizi alle applicazioni client J2EE fornisce un ampia varietà di servizi : • Tool per la gestione delle performance e del workload • Tool per la gestione della sicurezza • Tool per la gestione delle risorse • Tool per la gestione delle transazioni • Tool per la configurazione e il deployment di una applicazione 2.2.1 J2EE: il container Il container è un entità logica all’interno di un server J2EE, essenzialmente gestiscono tutte le componenti che sono state sottoposte ad un processo di deployment su un server J2EE. Il container è spesso definito come un ‘entità astratta perché né il client né le componenti serverside invocano le sue funzionalità. Possiamo quindi affermare che fornisce in maniera trasparente dei servizi alle componenti caricate e attive sul server: • Gestione delle transazioni • Gestione della sicurezza • Gestione della persistenza dei dati • Astrazione tra componenti e risorse tramite il meccanismo delle resource reference • Etc.. È importante citare e spiegare il meccanismo delle resource reference attraverso un esempio: nel caso in cui una componente usa un database il programmatore può definire una resource reference per il linking al DB. Successivamente il responsabile del deployment definisce il mapping tra resourse reference e DB fisico. Qual è il vantaggio di questo procedimento? Programmazione su Reti 2 2004/2005 Pagina 8 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 Il codice non è legato (non è hard-coded ) ad uno specifico database ma in fasi successive è possibile modificare la locazione o altre proprietà del database senza alterare il codice dell’applicazione server-side. Un’altra importante caratteristiche sta nel fatto che gestisce il ciclo di vita delle componenti caricate e attive sul server J2EE. Nel caso degli EJB, il container gestisce il loro ciclo di vita tramite un meccanismo di pooling. Questo meccanismo varia per ogni tipologia di bean ma possiamo generalizzarlo attraverso questi principi di base: • • • • Crea un pool di istanze dello stesso bean Una volta che il numero di bean eccede un limite fissato (del container) o allora il container può decidere di farne lo swap portando lo stato di un bean che era in memoria principale su memoria secondaria. o Questo processo prende il nome di Passivation All’atto della invocazione su un bean passivato o questo viene riportato all’interno del pool in memoria principale o eventualmente un’altra istanza può essere passivata o questo processo prende il nome di Activation Crea o “distrugge” nuove istanze in base alle esigenze Programmazione su Reti 2 2004/2005 Pagina 9 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 3. Enterprise Java Bean Gli Enterprise Java Beans sono le componenti più importanti della piattaforma J2EE; rappresentano una vera e propria tecnologia per l’implementazione della logica di business di un sistema distribuito ad oggetti: La SUN definisce così gli EJB: “La architettura EJB è una architettura a componenti per lo sviluppo e la realizzazioni di applicazioni business distribuite basate su componenti. Le applicazioni scritte con EJB sono scalabili, transazionali e sicure. Queste applicazioni possono essere scritte una volta e poi portate su ogni piattaforma server che supporti lo standard EJB” Possiamo dare una definizione molto più ridotta ma comunque esplicativa degli EJB: “EJB è un modello di programmazione a componenti utilizzato per implementare la logica di business delle nostre applicazioni server side “ 3.1 La classificazione Possiamo classificare gli EJB in tre categorie : o Session bean o Entity bean o Message-driven bean I Session Bean rappresentano logicamente una sessione di operazioni di cui un applicazione client o un altro bean può aver bisogno; praticamente sono delle classi che implementano la logica di business in un’ applicazione server-side. Se pensiamo alla descrizione di uno scenario da implementare a livello software i session bean con i loro metodi implementano le azioni, rappresentate dai verbi della discussione. Gli Enity Bean rappresentano logicamente i dati di business tipici di un applicazione distribuita; praticamente sono delle classi che fisicamente sono mappate in tabelle di un database relazionale e le loro istanza sono le tuple delle corrispondenti tabelle. Se pensiamo alla descrizione di uno scenario da implementare a livello software gli entity bean con i loro metodi implementano i soggetti e i sostantivi dell’analisi logica del periodo. I Message Driver Bean sono molto simili ai Session Bean con la differenza che non hanno metodi che vengono invocati “da remoto” da un applicazione client, ma gestiscono la comunicazione con altri sistemi o all’interno dello stesso container tramite lo scambio di messaggi asincroni e l’utilizzo del protocollo JMS. Bisogna fare un ulteriore distinzione all’interno degli EJB che riguarda gli EJB locali e quelli Programmazione su Reti 2 2004/2005 Pagina 10 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 remoti. Gli EJB locali possono essere chiamati (stiamo parlando dei loro metodi logicamente) all’interno dello stesso container da altri bean mentre quelli remoti possono essere invocati da altre applicazioni tramite la rete e l’utilizzo di protocolli distribuiti come RMI-IIOP; quest’ultimo lega il modello ad oggetti di JAVA(RMI) e il protocollo di trasporto di CORBA (IIOP). Un EJB può essere sia accessibile in locale che da remoto, sostanzialmente devono essere implementate interfaccie locali e remote (dopo vedremo un esempio). La distinzione tra EJB locali e EJB remoti ha senso perché è possibile garantire la comunicazione tra oggetti all’interno dello stesso container senza ricorrere a protocolli di networking, garantendo prestazioni più efficienti. 3.1.1 Architettura di un applicazione distribuita Un’applicazione distribuita può essere tipicamente composta da: • • • • La componente di dialogo con un database (local entity bean) La componente di supporto alla logica di business (stateless local session bean) La componente che implementa la logica di business distribuita (stateless o stefeful remote session bean) La componente che gestisce l’invio e la ricezione di messaggi con altri sistemi( messagedriven beans) All’interno dello schema sono stati citati l’attributo stateless e l’attributo stateful che saranno spiegati meglio, facendo riferimento ad ogni bean. 3.2 Session Bean Prima abbiamo definito i Session Bean in questo modo: I Session Bean rappresentano logicamente una sessione di operazioni di cui un applicazione client o un altro bean può aver bisogno; praticamente sono delle classi che implementano la logica di business in un’ applicazione server-side. Se pensiamo alla descrizione di uno scenario da implementare a livello software i session bean con i loro metodi implementano le azioni, rappresentate dai verbi della discussione. Un session bean è una componente server-side dalla vita breve, poiché esprime esclusivamente il comportamento di una serie di interazioni con l’utente (sessione). Tipicamente i session bean sono in memoria, soggetti a tutte le caratteristiche della memoria principale: volatilità e non persistenza; il container può gestire il loro accesso attraverso tecniche di caching. Programmazione su Reti 2 2004/2005 Pagina 11 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 Sono di seguito presentate due tipologie di Session Bean : • • Stateful Session Bean Stateless Session Bean In effetti tutti i bean mantengono una conversazione con uno o più client e a seconda del tipo di conversazione esistono le tue tipologie di session bean prima citate. Se un applicazione Client accede, per la richiesta di un servizio, ad uno Stateful Session Bean lo stato della conversazione viene mantenuto. La conversazione consiste nell’invocazione di una serie di metodi sul bean e lo stato invece è rappresentato da una o più variabili d’istanza del Session Bean. Se un applicazione Client accede ,per la richiesta di un servizio ,ad uno Stateless Session Bean lo stato della conversazione non viene mantenuto. La conversazione consiste nell’invocazione di un singolo metodo ,dove vengono passati tutti i parametri necessari alla richiesta del servizio. Per quanto riguarda uno Stateless Session Bean ,il container non assume responsabilità circa la vita del bean: può decidere di tenerlo in vita oppure di ucciderlo ,allo scopo di gestire un pool di bean (per ottimizzare le prestazioni).Il bean non ha uno stato da salvare ma può comunque avere una serie di una o più variabili d’istanza ,necessarie alla computazione. Per quanto riguarda uno Stateful Session Bean, la gestione del suo ciclo di vita non è così semplice come per il caso dei Stateless Session Bean ,in quanto è necessario memorizzare in qualche maniera lo stato della conversazione con il bean. La soluzione a questo problema sta nella gestione del pool di bean attraverso il meccanismo di activation e passivation prima descritto a proposito del container, cioè: • • • • Il container crea un pool di istanze dello stesso bean Una volta che il numero di bean eccede un limite fissato (del container) o allora il container può decidere di farne lo swap portando lo stato di un bean che era in memoria principale su memoria secondaria. o Questo processo prende il nome di Passivation All’atto della invocazione su un bean passivato o questo viene riportato all’interno del pool in memoria principale o eventualmente un’altra istanza può essere passivata o questo processo prende il nome di Activation Crea o “uccide” nuove istanze in base alle esigenze. Affinché vada in porto il salvataggio dello stato di un Session Bean è necessario che la interface javax.ejb.EnterpriseBean (vedremo dopo) estenda java.io.Serializable; in questo modo ogni bean implementa l’interface Serializable. In pratica, ogni variabile del bean viene considerata stato, se: Programmazione su Reti 2 2004/2005 Pagina 12 di 38 Enterprise Java Beans e Web Services • • Data:20/05/2005 È un tipo primitivo non marcato come transient È un oggetto (estende Object) 3.2.1 Implementazione di un Session Bean L’implementazione di un Session Bean prevede la realizzazione delle seguenti componenti: • La classe di Bean • La interface Remote • La interface Home • Il deployment descriptor • Eventuali interface locali Descriviamo ora cosa intendiamo per ogni componente, il ruolo di ognuna di esse. 3.2.1.1 La classe di Bean La classe di Bean specifica la logica di business. Nel momento in cui stiamo implementando la classe principale del bean è essenziale che essa implementi l’interface javax.ejb.SessionBean , che risulta a tutti gli effetti un interface marker. Le interface marker che si utilizzano per l’implementazione di una classe di Bean sono: • • • javax.ejb.SessionBean (nel caso dei Session Bean) javax.ejb.EntityBean (nel caso degli Entity Bean) javax.ejb.MessageDrivenBean (nel caso dei MessageDriven Bean) Queste interfacce estendono javax.ejb.EnterpriseBean, che a sua volta estende java.io.Serializable; ciò significa essenzialmente che è possibile serializzare un’ istanza della classe e quindi trasmetterla su rete o memorizzarla su disco, nel caso in cui è in atto un processo di activation e passivation. Un’ istanza della classe di Bean non rappresenta un vero proprio oggetto remoto perché il client non invoca mai metodi remoti su di essa. 3.2.1.2 L’oggetto EJB e l’interface remota del bean L’oggetto EJB espone al client i metodi del nostro bean. Possiamo osservare la figura 3.1 che descrive in dettaglio il ruolo e le funzionalità dell’oggetto EJB. Esso implementa l’interface remota del bean; il programmatore devo solo: • Implementare l’interface remota del bean o In cui si pubblicizziamo tutti metodi che è possibile invocare da un’applicazione client E le modalità di utilizzo del metodo (parametri e tipo di ritorno) Programmazione su Reti 2 2004/2005 Pagina 13 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 o L’interface remota deve estendere l’interface javax.ejb.EJBObject L’oggetto EJB viene generato automaticamente da parte dei tool del container forniti dal produttore,sulla base delle indicazioni fornite dalla interface remote fornita dall’ implementatore. Alla luce di queste notazione è possibile comprendere i 5 passi descritti nella figura 3.1 , azzardando nel dire che l’ oggetto EJB è il nostro Request Interceptor ,citato nelle pagine precedenti. Figura 3.1 3.2.1.3 L’oggetto Home e l’interface di Home Adesso ripetiamo il discorso fatto nel precedente sottoparagrafo, però trattando della Home di un oggetto EJB. Infatti dobbiamo chiederci spontaneamente: ma come fa l’applicazione client a ottenere un riferimento remoto ad un oggetto EJB? Rispondiamo dicendo che l’applicazione Client contatta precedentemente da remoto un oggetto Home che restituisce un riferimento remoto all’oggetto EJB. La figura 3.2 riassume l’intero processo di invocazione di un metodo da remoto di un’ applicazione Client ,compreso la comunicazione tra Client e oggetto Home. Programmazione su Reti 2 2004/2005 Pagina 14 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 Figura 3.2 L’oggetto Home deve : creare oggetti EJB,trovare oggetti EJB esistenti oppure rimuovere oggetti EJB. È a tutti gli effetti una factory,responsabile per creazione e distruzione di oggetti EJB. Un’altra domanda è lecita : ma come fa l’oggetto Home a sapere la inizializzazione dell’oggetto EJB? Ciò è possibile tramite l’implementazione dell’interface Home del nostro Bean;il programmatore devo solo: • Implementare l’interface remota della Home o In cui si pubblicizziamo tutti metodi che è possibile invocare da un’applicazione client per creare un oggetto EJB E le modalità di utilizzo del metodo (parametri e tipo di ritorno) o L’interface remota deve estendere l’interface javax.ejb.EJBHome,che estende Remote; quindi l’oggetto Home può trovarsi anche su una macchina diversa dall’oggetto EJB. L’oggetto Home viene generato automaticamente da parte dei tool del container forniti dal produttore,sulla base delle indicazioni fornite dalla interface remote fornita dall’ implementatore. 3.2.1.4 Assemblaggio e Deployment L’ultima operazione da effettua per completare l’implementazione del Session Bean è assemblare le varie componenti prodotte. In realtà bisogna anche realizzare,come vedremo in seguito,il deployment descriptor del Session Bean ,che contiene tutte le informazione del bean,dal nome della sua interface remota al nome della interface di Home ,al nome dei servizi di middleware di cui ha bisogno etc… Infine è necessario citare anche la necessità di implementare le interfacce locali per il Bean e per Programmazione su Reti 2 2004/2005 Pagina 15 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 la Home, nel caso in cui si realizza un Local Session Bean. Le due interfaccie devono estendere rispettivamente: javax.ejb.EJBLocalObject e javax.ejb.EJBLocalHome. L’operazione di assemblaggio consiste nel creare un EJB-JAR file che contiene: • • • • • • La classe di Bean la interface Remote la interface Home il deployment descriptor eventuali interface locali file specifici per il fornitore del container In passato non veniva fatta alcuna differenza tra la conoscenza di: o o o o Un linguaggio di programmazione Tecnologie di database Tecnologie di networking Amministrazione di sistema. Inoltre per la realizzazione di un applicazione web distribuita, un programmatore doveva conoscere assolutamente anche il linguaggio html. Oggi grazie all’utilizzo di una piattaforma come J2EE i ruoli di programmatore WEB ,di programmatore della logica di business ,di responsabile del deployment o di amministratore del sistema sono ben distinti. Si distinguono due figure chiave per il completamento dell’attivazione di un applicazione server-side: L’assemblatore Mette insieme le componenti implementate dagli sviluppatori al fine di realizzare un applicazione distribuita. Il responsabile del deployment: Carica l’applicazione lato server sulla piattaforma affinché possa rispondere alle richieste effettuate dal lato client Sono entrambi integratori di sistema. Programmazione su Reti 2 2004/2005 Pagina 16 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 4. Gli Entity Bean Gli entity sono oggetti persistenti che possono essere memorizzati in memoria secondaria, servono a modellare i dati necessari agli obiettivi della applicazione, in pratica, possono sostituire completamente l’utilizzo di database; sono offerti dal container al programmatore con due livelli di servizio: • • a carico del container a carico (parziale) del programmatore Il vecchio stile di programmazione prevede di scrivere un programma che effettua query su un database. Gli oggetti, invece, offrono una gestione semplificata ed efficiente: la possibilità di creare un tipo di oggetto (classe) che contenga non solo dati ma anche i metodi a cui i dati devono essere soggetti (compressione, aggiornamento, etc.); la ereditarietà può essere utilizzata come direste “questa tabella deriva da quest’altra tabella”, in più i servizi di middleware impliciti offrono caratteristiche come: transazioni, accessibilità su rete, sicurezza, caching per prestazioni. La persistenza è ottenuta mediante la memorizzazione su memoria secondaria in modo da ottenere anche altri vantaggi quali il recovery da crash, tecniche di roll-back per le transazioni, compatibilità verso applicazioni legacy. Le tre tecniche tipicamente utilizzate per la persistenza dei dati sono: • • • la serializzazione degli oggetti Java mapping oggetto/relazionale database ad oggetti La serializzazione di Java E’ un meccanismo per rappresentare in maniera compatta, completa e seriale (flusso di bit) un oggetto Java con tutti i suoi campi ricorsivamente serializzati • • Utilità: o invio su rete (passaggio parametri su RMI) o persistenza oggetti in un file, database, contesto JNDI etc. Svantaggi: o inefficienza nell’ usare delle query su oggetti serializzati per poterne selezionare una parte o necessario ricostruire l’oggetto Java per poterne accedere i campi Mapping oggetto/relazionale Si usa un DB relazionale standard, si decompone l’oggetto in tutte le sue parti che vengono memorizzate separatamente; il salvataggio di un oggetto Java in un DB consiste nell’utilizzare uno o più righe di una (o più) tabelle per scrivere i dati dell’oggetto. Per poter riottenere Programmazione su Reti 2 2004/2005 Pagina 17 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 l’oggetto, basta creare un oggetto nuovo, e popolarne i campi con i dati presi dal DB. L’utilità del mapping permette l’uso di query sugli oggetti per esempio, ricercare i conti correnti che sono in rosso (saldo < 0) diventa un semplice statement SQL, ciò comporta facilità di ispezione e controllo della consistenza, un’interazione facilitata con sistemi legaci, infatti integrare un DB relazionale con un sistema preesistente è naturale, data la natura di sistemi di gestione di BD di questi sistemi. Database a oggetti I database a oggetti sono un’evoluzione dei DB relazionali, permettono di memorizzare (direttamente) oggetti, non viè quindi nessuna necessità di effettuare il mapping: un oggetto viene scritto/letto in un ODB come tale utilizzando le API del database. Le query vengono effettuate mediante l’Object Query Language che astrae le query relazionali a livello degli oggetti. I vantaggi dei DB a oggetti sono: • le prestazioni o dato che vengono mantenute le relazioni tra oggetti, si può “navigare” tra oggetti correlati (come un cliente ed il suo conto corrente) senza dover effettuare le costose join relazionali (NB: in contesti semplici, un DB relazionale è più efficiente) • Scalabilità • Sicurezza Due sono le tipologie di oggetti nelle applicazioni distribuite: • Le componenti della logica della applicazione che forniscono i metodi per i compiti comuni; nella descrizione delle componenti rappresentano i “verbi” = session beans • Le componenti con dati persistenti, ovvero oggetti che usano qualche meccanismo di persistenza per rappresentare dati; nella descrizione delle componenti rappresentano i “sostantivi” = entity beans Due sono le strade possibili per chi vuole scrivere una applicazione con EJB, ovvero: 1. scrivere session bean e poi usare JDBC per conettersi ad un DB (Session+JDBC) 2. usare gli entity bean (Entity) Vantaggi e Svantaggi • Controllo della applicazione o Session+JDBC fa mantenere il controllo al programmatore: quando e come si Programmazione su Reti 2 2004/2005 Pagina 18 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 scrive sul DB, come si strutturano i dati nelle tabelle, etc. • Efficienza o se è a carico del container, attenzione alla configurazione del server un solo statement SQL potrebbe essere tradotto in un certo numero di statement. Una analogia con il passaggio di parametri: Session+JDBC = Passaggio parametri per valore; Entity = Passaggio parametri per riferimento o Efficienza in locale: uguali con Session+JDBC e Entity la query restituisce un data set al session bean; o Efficienza in remoto: attenzione alla soluzione Entity: con GUI client / EJB session che lavorano da remoto c’è bisogno di un session che faccia il wrapping dei dati per inviarli tutti insieme sul client; • Caching I session bean non possono essere posti in cache, di conseguenza non vi è nessun miglioramento sensibile delle prestazioni; o Se gli entity bean rappresentano dati condivisi allora il caching permette di riutilizzare bean, vi è quindi un miglioramento notevole: basta pensare agli entity bean che rappresentano i 100 libri più venduti di Amazon: verranno tenuti sempre in cache e riutilizzati; o In presenza di dati non condivisi la soluzione Session+JDBC può essere più efficiente. SQL scritto dal programmatore, di solito, è più efficiente di quello generato dal container; o • OO vs. Procedurale o A seconda del tipo di applicazione è più naturale un approccio relazionale (tabelle e procedure) oppure un approccio Object Oriented in ognuna dei due casi, risulta più adatto: Session-JDBC: approccio procedurale a tabelle di un DB per dati di grandi dimensioni ma di scarsa strutturazione (es.: grandi anagrafiche), spesso ereditati da applicazioni legaci); Entity: approccio OO a dati complessi ed eterogenei riusabili e scalabili; • Indipendenza dagli schemi o Facilità di manutenzione: la gestione di tabelle tipicamente complessa su grandi dimensioni (horror stories: 1 anno/uomo per poter aggiungere due colonne in un database); o Entity bean permette di sviluppare ad uno strato superiore rispetto la struttura del Programmazione su Reti 2 2004/2005 Pagina 19 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 DB, cosa possibile anche con Session+JDBC ma con grande abilità. Ciò comporta la possibilità di seguire l’evoluzione del sistema basandosi su OO; • Facilità di uso e sviluppo rapido o Sicuramente Session+JDBC sono pù semplici e familiari da utilizzare, ovviamente è necessario valutare l’impatto sul team; o Esistono sistemi rapidi di sviluppo per Entity bean che permettono di passare dal design UML al bean: vale la pena utilizzarli su grandi progetti, allo scopo di non perdere tempo scrivendo XML tutto il tempo che si era guadagnato non scrivendo codice Java; • Migrazione e sistemi legaci o La maggior parte dei sistemi si scontra con i sistemi legacy progettati in tabelle (se va bene!) il che permette di riutilizzare codice SQL funzionante, testato da anni e che nessuno potrebbe avere voglia/tempo/competenza/fegato da riscrivere! In questo caso Session+JDBC può avere delle giustificazioni; o Entity ha vantaggi a medio-lungo termine ma sul breve, in questo caso, può offrire dei rischi; 4.1 Differenza tra session ed entity beans Un session bean è una componente essenzialmente dalla vita breve poiché esprime esclusivamente il comportamento di una serie di interazioni con l’utente (sessione). Un entity bean è una componente dalla vita potenzialmente molto lunga in quanto rappresenta i dati come oggetti persistenti e quindi dalla vita pari a quella di dati su memorie secondarie. Un entity bean è costituito da un insieme di file standard per EJB, ovvero: interface, locali, remote, home, deployment descriptor, etc. Le uniche differenze risiedono: nella classe di entity bean che assegna la definizione dei dati in un database con i metodi per manipolarli, e nella classe di primary key che rende ogni entity bean diverso. Gli Entity EJB sopravvivono ai crash di sistema essendo oggetti persistenti assegnati a dati in memoria secondaria. Sono una vista (view) in un database NON devono essere concepiti come una visione in memoria di dati su memoria secondaria, in quanto l’update è costante e a carico del container. Ogni entity deve avere i metodi ejbLoad() e ejbStore() chiamati dal container (e mai del client/sviluppatore); alcuni dati sono soggetti ad accesso concorrente è quindi necessario risolvere il problema della consistenza. Gli Entity EJB possono essere messi in un pool: la costosa creazione/distruzione di oggetti viene ammortizzata per un lungo periodo di tempo, ogni oggetto entity viene quindi riciclato per usi futuri anche (e soprattutto) per dati diversi dello stesso tipo. La gestione del pooling è a totale carico del container che si occupa di riutilizzare in maniera coerente oggetti entity al fine di Programmazione su Reti 2 2004/2005 Pagina 20 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 ottimizzare le prestazioni (callback: ejbActivate() e ejbPassivate() ). Qualcuno deve scrivere, in qualche momento, il codice che accede al database per poter assicurare la persistenza degli oggetti entity : o se lo fa lo sviluppatore, allora si ha un bean-managed persistent bean (BMP) o altrimenti, lo fa il container e si ha un container-managed persistent bean (CMP): lo sviluppatore informa solamente del tipo di operazioni e della struttura del bean, poi il container a deployment time crea il codice necessario…enorme risparmio di codice (al costo di affidarsi alla tecnologia EJB!). All’atto della creazione e rimozione di un entity si deve fisicamente creare nel DB di supporto una riga in una tabella (creazione) oppure si deve cancellare. L’oggetto Home dell’Entity si occupa di effettuare la creazione dell’entity che prende come parametri i dati necessari per riempire il record e restituisce un parametro di chiave primaria (come definito dallo sviluppatore) E’ necessario specificare, per gli entity bean-managed, uno (o più) metodi di finder() che servono per poter implementare la ricerca di un dato bean, corrispondono di solito ad una SELECT SQL; ovviamente, se si usa un DB, si possono modificare i dati direttamente sul DB (utile per i legacy) e i cambi sono riflessi sull’entity. Attenzione alla configurazione del container per i problemi di caching (coerenza)! Il metodo getPrimaryKey() restituisce la chiave associata alla istanza del bean essenzialmente serve per evitare che ci siano problemi con il riuso ed il pooling di risorse: si chiama per poter sapere ejbLoad() da che riga della tabella deve caricare i dati oppure si chiama per ejbRemove(). 4.2 BMP e CMP E’ necessario che sia scritto il codice che accede al database per poter assicurare la persistenza degli oggetti entity : • • se lo fa lo sviluppatore, allora si ha un bean-managed persistent bean (BMP Entity Bean) altrimenti, lo fa il container e si ha un container-managed persistent bean (CMP Entity Bean) lo sviluppatore informa solamente del tipo di operazioni e della struttura del bean, poi il container a deployment time crea il codice necessario L’implementazione di un BMP entity bean è complessa e tediosa, e poco utilizzata di conseguenza sposto l’attenzione più verso i CMP. Tipicamente gli entity bean implementano solamente le interfacce local, in quanto tipicamente vengono chiamati solamente da altri oggetti (EJB session, servlet, etc.) che sono locali per motivi di testing, viene comunque di solito fornita una interface remota (che viene soppressa in produzione). Un CMP è costituito dall’entity bean (la logica presente nei dati) e dalla rappresentazione persistente di tali dati. Il meccanismo del subclassing consiste in due fasi il programmatore scrive una classe astratta e il container (a deployment time) la rende “concreta” Programmazione su Reti 2 2004/2005 Pagina 21 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 derivando da essa una classe con i metodi per la persistenza. In maniera simile a come vengono specificati gli attributi negli ambienti distribuiti (dove la sintassi non offre tale possibilità dichiarando, cioè, i metodi accessori) si specificano nella classe astratta esclusivamente i metodi accessori lasciando al container (durante il deployment) il compito di generare i campi nella classe concreta derivata, ovviamente, questo vale esclusivamente per i campi persistenti, altri campi di uso da parte del bean vanno dichiarati nella classe astratta dal programmatore. L’abstract persistence schema: è la dichiarazione nel deployment descriptor dei campi che devono essere resi persistenti. Lo scopo è di permettere all’atto del deployment di generare il codice necessario per la persistenza. Si dichiara: • • • • • la versione utilizzata di EJB il nome dell’abstract persistence schema il nome dei campi persistenti consistenti con il nome dei metodi accessori (get,set) consistenti con le regole di naming (prima lettera minuscola) 4.3 EJB Query Language Viene fornito come linguaggio per effettuare le query, è orientato agli oggetti con una sintassi SQL-like; dovrebbe essere portabile in pratica non lo è! Viene inserito nel deployment descriptor che per ogni metodo descrive il nome del metodo, i parametri, la query EJB-QL da eseguire. Una altra differenza tra BMP e CMP entity bean è la presenza dei metodi di select: sono come un metodo finder ai quali non è possibile accedere dal client (attraverso la home interface o la component interface); viene usato internamente come metodo per accedere ai dati per operazioni sul DB che non devono essere esposte, per reperire dati da altri entity beans con i quali il bean ha relazioni: possono restituire non solo entity beans (o loro collection) ma anche campi (gestiti dal container) o loro collection. Le differenze tra Bean Managed Persistent e Container Managed Persistent risiedono esclusivamente nella classe dell’entity bean e nel deployment descriptor. Questo permette una facile transizione tra BMP e CMP e viceversa facilitando lo sviluppo della logica dei dati che risulta così indipendente dalle scelte relative alla persistenza dei dati. Tutto il lavoro risparmiato con i CMP viene di fatto demandato a: • • al container che si occupa della persistenza alla fase di deployment che richiede una complessa dichiarazione delle caratteristiche del bean Quindi, il lavoro del “programmatore” colui/colei che programma diventa anche lavoro di “dichiaratore” colui/colei che dichiarano nel deployment descriptor quali sono i dati di cui assicurare la persistenza e in cosa si traducono le operazioni necessarie sugli oggetti Le fasi di deployment: Programmazione su Reti 2 2004/2005 Pagina 22 di 38 Enterprise Java Beans e Web Services • • • • Data:20/05/2005 Configurazione del database reference Creazione del bean: o scelta delle classi o persistenza: scelta dei campi o persistenza: EJB-QL per i metodi o persistenza: informazioni per la creazione della tabella SQL Verifica del bean (se rispetta le specifiche del container) Deployment sul container 5. JMS Prima di parlare dell’ultimo tipo di bean bisogna parlare di JMS ovvero Java Message Service. E’ un servizio Servizio di Messaging per componenti software peer-to-peer che permette di scambiare messaggi tra peer che possono assolvere il ruolo di producer o consumer di messaggi in maniera intercambiabile (P2P). E’ un servizio alla base del Middleware Orientato ai Messaggi (MOM): trasmissione asincrona e debolmente accoppiata (loosely couplet). Il motivo per cui si è scelto di utilizzare un meccanismo di messaging è che il tradizionale meccanismo di comunicazione (Remote callout) comporta delle situazioni non adeguatamente risolte da RMIIIOP ovvero: • • chiamate bloccanti e sincrone, il client si blocca fino a quando il server non completa la chiamata, questo vale anche con le implementazioni non bloccanti (call-back, etc.) che servono solo a ridurre il problema; il server deve essere in esecuzione quando il client effettua la chiamata Il Messaging è una alternativa alle invocazioni remote: viene utilizzato un intermediario (software di middleware) che offre il servizio di message permettendo lo stile di programmazione asincrono; le chiamate sono “veramente” asincrone: • il client invia il messaggio e continua con le sue computazioni, questa è un’importante caratteristica quando non è necessario un feedback immediato al client (o all’utente). Il ruolo dell’intermediario sostituisce il server (destinazione del messaggio): se il server non è in esecuzione, il middleman mantiene il messaggio del client, sarà compito dell’intermediario recapitare il messaggio quando il server sarà di nuovo in esecuzione (garanzia di recapito). L’intermediario può agire (se configurato opportunamente) in maniera da distribuire il messaggio a più destinatari (broadcasting del messaggio), utile per: facilità di programmazione, efficienza (il client non deve effettuare n spedizioni, ma sarà l’intermediario a svolgere il compito). Java Message Service è un’API sviluppata dalla Sun; due sono le componenti principali: Programmazione su Reti 2 2004/2005 Pagina 23 di 38 Enterprise Java Beans e Web Services • • Data:20/05/2005 Application Programming Interface (API): permette di scrivere codice per inviare e ricevere messaggi; Service Programming Interface (SPI) permette di scrivere JMS drivers per poter usare implementazioni MOM specifiche, simile al concetto di driver in JDBC e JNDI, permette la modularità e indipendenza dalla piattaforma di MOM utilizzata. Due sono le modalità presenti nei sistemi MOM esistenti: • • point-to-point o I messaggi vengono indirizzati ad una singola coda da un sender; i receiver estraggono i messaggi dalla coda per leggerli; la coda memorizza i messaggi fino a quando essi sono estratti da un receiver oppure il messaggio scade di validità (expiration) Tre sono le caratteristiche fondamentali: I messaggi hanno un solo receiver Il sender ed il receiver non hanno dipendenze temporali il receiver può prelevare il messaggio anche se esso è stato spedito prima che il receiver fosse attivo. Il receiver fa l’acknowledgment del messaggio ricevuto. o In generale è buona norma usare il dominio point-to-point quando si vuole che: ogni messaggio deve essere ricevuto in maniera affidabile da esattamente un receiver publish/subscribe o I messaggi vengono indirizzati ad un topic (una sorta di bullettin board) da un publisher e i subscriber ricevono i messaggi dal topic. La coda memorizza i messaggi solamente per poterli distribuire a tutti i subscriber. Le caratteristiche fondamentali del publish/subscribe sono: I messaggi possono avere multipli subscriber Il publisher ed il subscriber hanno dipendenze temporali Il subscriber può prelevare solo i messaggi che sono stati pubblicati dopo la sua sottoscrizione Per poter ricevere messaggi, il subscriber deve essere attivo (esistono le durable subscription in cui il subscriber riceve messaggi anche se temporaneamente non attivo) o Il dominio publish/subscribe viene utilizzato quando si vuole che i messaggi devono essere spediti/ricevuti da client multipli ed anonimi Le modalità di ricezione dei messaggi (i messaggi sono inerentemente asincroni) sono due: • sincrona: o un receiver/subscriber chiama esplicitamente il metodo receive() (bloccante oppure fino ad un timeout definibile ) • asincrona: o un receiver/subscriber registra un message listener presso un consumer: quando Programmazione su Reti 2 2004/2005 Pagina 24 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 arriva un messaggio, viene chiamato il metodo onMessage() del Message Listener 5.1 MDB Un’idea interessante fu proposta nella versione 2.0 di Enterprise JavaBeans, ovvero “Permettere ad un EJB di poter ricevere messaggi JMS, in una qualche maniera”. I Message Driven Bean sono EJB a tutti gli effetti potendo quindi godere di tutti i servizi forniti dal container, ma sono dei consumatori di messaggi: i client possono esclusivamente inviare messaggi e quindi non ci sono interfacce da definire di alcun tipo c’è un solo metodo da implementare che è lo stesso della interface MessageListener cioè onMessage(). Non ci sono valori da restituire né eccezioni da lanciare, non c’è stato da mantenere (gli MDB sono stateless). Un MDB deve implementare le interfacce MessageDrivenBean e MessageListener; la classe deve essere pubblica (non astratta o final) deve implementare un metodo ejbCreate() e un metodo ejbRemove() pubblici, non static/final, senza argomenti o eccezioni della applicazione. Deve contenere un costruttore pubblico senza argomenti, non deve definire metodi final. I vincoli da seguire per onMessage() sono: il metodo deve essere pubblico (e non dichiarato final o static), il tipo di ritorno deve essere void, non deve lanciare eccezioni specifiche della applicazione (ma solo eventualmente quelle EJB), non deve gestire le transazioni di per sé (questo viene fatto settando il parametro corretto nel descriptor file). Programmazione su Reti 2 2004/2005 Pagina 25 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 6. EJB e Web Services Come già presentato in precedenza, gli ejb sono stati progettati per avere un alto grado d’interoperabilità verso altri linguaggi di programmazione, affinché sia possibile integrare in un'unica piattaforma sistemi sviluppati con tecnologie diverse, soprattutto per il riuso di sistemi legasy. In modo nativo un sistema sviluppato con ejb permette di interagire tramite: • • • Applicazioni browser-based, in cui il lato server è implementato con JSP e Servlets Applicazioni basate sull’utilizzo di RMI-IIOP per la comunicazione tra client e EJB lato Server (implicitamente si ha così l’integrazione in sistemi sviluppati con CORBA) Applicazioni basate sullo scambio di messaggi utilizzando JMS Volendo integrare il sistema implementato con altri che non utilizzano i sistemi descritti, si ricorre all’utilizzo dei web services. Inoltre i due ultimi sistemi d’interazione anche se più efficienti non sono utilizzati per interagire a traverso reti esterne all’intranet aziendale, aumentando così la sicurezza interna alla rete aziendale. 6.1 Esportare gli EJB tramite web services Le soluzioni principali per esportare gli ejb tramite web services sono sostanzialmente le seguenti: 6.1.1 Soluzioni proprietarie degli EJB container Quasi tutti i container permettono di esportare i propri EJB come web services. Nel caso di SUN JavaTM System Application Server Platform Edition 81, all’atto del deployment si specifica di voler esportare l’ejb come web services. Il tool chiederà di inserire il file WSDL che descrive il servizio ed un file XML per ulteriori informazioni che serviranno al container all’atto del deployment (stessa funzionalità del file WSDD di Axis). 6.1.2 Utilizzare un motore SOAP esterno all’EJB container 6.1.2.1 Wrapper Utilizzando un motore SOAP esterno all’EJB container, posso implementare un web services che fa da wrapper tra i miei EJB ed il client SOAP. Il web services implementerà al suo interno tutta la logica per l’accesso all’EJB2. La presente soluzione è sempre applicabile, con qualsiasi sistema si utilizza. In realtà è 1 2 Su cui abbiamo effetuato i test. Liberamente scaricabile dal sito della Sun nella sezione J2EE. Utilizzando RMI-IIOP o JMS per interagire con esso. Programmazione su Reti 2 2004/2005 Pagina 26 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 molto più utile, quando non si vuole esportare esattamente la logica implementata negli EJB, mascherandone parte di essa. 6.1.2.2 Soluzione offerta da AXIS Axis permette d’interagire con gli EJB di tipo Session Stateless in modo semiautomatico, tramite l’utilizzo di uno dei suoi tanti provider. Precisamente il provider “Java:EJB”. Non serve altro che scrivere un file WSDD per il deployment su axis dei servizi che si vogliono esportare inserendo come parametri al servizio i seguenti attributi: beanJndiName: il nome registrato nell’architettura JNDI del Session Bean Stateless con cui si vuole interagire; homeInterfaceName: il nome dell’interfaccia home remota; remoteInterfaceName: il nome dell’interfaccia remota del servizio; jndiContextClass: il nome della classe che implementa l’interfaccia JNDI; jndiURL: l’url del server di naming. 6.2 Esempio: HelloBean Vediamo di seguito un semplice esempio di session bean stateless che offre il servizio di hello. Per prima cosa illustriamo il codice dell’Ejb HelloBean. Per quanto riguarda le interfacce remote e locali mettono a disposizione un unico metodo che è quello di hello, che prende in input una stringa e ritorna una stringa. Hello.java import java.rmi.RemoteException; import javax.ejb.EJBObject; public interface Hello extends EJBObject { public String hello(String in) throws RemoteException; } HelloLocal.java import javax.ejb.EJBLocalObject; public interface HelloLocal extends EJBLocalObject { public String hello(String in); } La differenza sostanziale è che il metodo hello in locale non deve lanciare eccezioni remote. Per quanto riguarda le interfacce Home di seguito riportare, offrono il metodo create, il quale permette di “creare” un istanza di HelloBean è di accedervi tramite l’interfaccia remota o locale. HelloHome.java import java.rmi.RemoteException; import javax.ejb.CreateException; Programmazione su Reti 2 2004/2005 Pagina 27 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 import javax.ejb.EJBHome; public interface HelloHome extends EJBHome { public Hello create() throws RemoteException,CreateException; } HelloLocalHome.java import javax.ejb.CreateException; import javax.ejb.EJBLocalHome; public interface HelloLocalHome extends EJBLocalHome { public HelloLocal create() throws CreateException; } Fino a questo momento abbiamo creato soltanto interface dove abbiamo inserito le firme dei metodi che ci servono. L’implementazione di questi metodi è a carico del container tranne per i metodi di business (il metodo hello). A questo punto non ci resta che implementare la logica del bean. HelloBean.java import java.rmi.RemoteException; import javax.ejb.EJBException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; public class HelloBean implements SessionBean { public void ejbCreate() throws EJBException{ } public void ejbActivate() throws EJBException, RemoteException { } public void ejbPassivate() throws EJBException, RemoteException { } public void ejbRemove() throws EJBException, RemoteException { } public void setSessionContext(SessionContext arg0) throws EJBException, RemoteException { this.ctx = arg0; } public String hello(String in){ return "Ciao "+in; } private SessionContext ctx; } Programmazione su Reti 2 2004/2005 Pagina 28 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 La nostra classe implementa l’interfaccia javax.ejb.SessionBean, implementando i metodi che gli servono (in questo caso nessuno), e fornendo l’implementazione del metodo hello. A questo punto si compila il tutto è lo si inserisce in un file jar fornendo il file xml per il deployment3. Di seguito riportiamo parte del file ejb-jar.xml: <enterprise-beans> <session> <ejb-name>HelloBean</ejb-name> <home>HelloHome</home> <remote>Hello</remote> <local-home>HelloLocalHome</local-home> <local>HelloLocal</local> <ejb-class>HelloBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Bean</transaction-type> <security-identity> <use-caller-identity/> </security-identity> </session> </enterprise-beans> Dopo aver fatto il deployment sul container dobbiamo eseguire il deployment su axis per esportare il servizio di hello tramite web services. Utilizziamo il seguente file WSDD come descritto in precedenza. <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="HelloBean" provider="java:EJB"> <parameter name="beanJndiName" value="HelloBean"/> <parameter name="homeInterfaceName" value="HelloHome"/> <parameter name="remoteInterfaceName" value="Hello"/> <parameter name="allowedMethods" value="hello"/> <parameter name="jndiContextClass" value="com.sun.jndi.cosnaming.CNCtxFactory"/> <parameter name="jndiURL" value="iiop://localhost:3700"/> </service> </deployment> È molto importante che prima di eseguire il deploy su AXIS tramite Adminclient, bisogna copiare il file jar generato dall’AS per i client, nella directory {TomcatHome}\webapps\axis\WEB-INF\lib. Inoltre per far sì che AXIS possa accedere agli EJB bisogna copiare il file j2ee.jar (reperibile nelle distribuzioni di j2ee) nella cartella di Tomcat contenente le librerie condivise ({TomcatHome}\common\lib). A questo punto non ci resta che eseguire il client Soap che del tutto simile al client hello visto 3 Nel nostro caso è stato utilizzato il tool (Deploytool) fornito dalla Sun per creare in modo semiautomatico i file jar per il deployment. Programmazione su Reti 2 2004/2005 Pagina 29 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 nelle prime esercitazioni sui web services4. 6.3 Esempio: Skatestown Vediamo in quest’ultima parte un esempio più complesso d’interazione con più ejb. Vogliamo costruire un sistema software che permette di memorizzare dei prodotti commerciali ed inoltre il sistema dovrà permetterci di effettuare operazioni di ricerca sui prodotti memorizzati. Per ogni prodotto vogliamo memorizzare l’ID del prodotto, il suo nome, una descrizione e il prezzo base, mentre come operazioni che il sistema deve offrire vogliamo: inserire articoli, estrarre tutti i prodotti presenti e ricercare il prezzo di un prodotto tramite il suo ID. Il sistema sarà implementato utilizzando due ejb, il primo di tipo entity CMP che modellerà l’entità prodotto, permettendoci di rendere persistenti le informazioni sui prodotti. Mentre per le operazioni su di essi si utilizzerà un ejb di tipo session stateless che metterà a disposizione tre metodi per le tre operazioni richieste. Il diagramma illustra i due ejb. 6.3.1 Entity CMP: Product L’ejb product implementerà la persistenza dei dati sui prodotti. Non sarà fornita un’interfaccia remota, ma soltanto quella locale, questo permetterà l’accesso all’ejb solo all’interno del container, quindi le interazioni da remoto dovranno essere fatte con l’ejb session. Di seguito riportiamo l’interfaccia locale dell’entity e la sua home locale. 4 Il codice non viene riportato, si vedanoo gli allegati alla relazione. Programmazione su Reti 2 2004/2005 Pagina 30 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 ProductLocal.java import javax.ejb.EJBLocalObject; public interface ProductLocal extends EJBLocalObject { public String getName(); public void setName(String name); public String getDescription(); public void setDescription(String desc); public double getBasePrice(); public void setBasePrice(double price); public String getProductID(); } ProductLocaHomel.java import java.util.Collection; import javax.ejb.CreateException; import javax.ejb.EJBLocalHome; import javax.ejb.FinderException; public interface ProductLocalHome extends EJBLocalHome { ProductLocal create(String productID,String name,String desc,double price)throws CreateException; public ProductLocal findByPrimaryKey(String key)throws FinderException; public Collection findAll()throws FinderException; } Come spiegato in precedenza l’interfaccia locale espone metodi get e set per ogni attributo da rendere persistente, da notare che non c’è il metodo setProductID perché non deve essere possibile cambiare la chiave primaria una volta creato un prodotto5. Per la classe home ci sono tre metodi: il primo crea un nuovo prodotto, il secondo permette la ricerca su chiave primaria ed in fine il terzo metodo estrae tutti i prodotti presenti e ritorna una collezione. Presentiamo ora l’implementazione dell’entity bean: ProductBean.java import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EJBException; import javax.ejb.EntityBean; import javax.ejb.EntityContext; 5 Equivarrebbe ad una cancellazione e reazione di un nuovo prodotto. Programmazione su Reti 2 2004/2005 Pagina 31 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 import javax.ejb.RemoveException; public abstract class ProductBean implements EntityBean { protected EntityContext ctx; public ProductBean(){} public abstract String getName(); public abstract void setName(String name); public abstract String getDescription(); public abstract void setDescription(String desc); public abstract double getBasePrice(); public abstract void setBasePrice(double price); public abstract String getProductID(); public abstract void setProductID(String ID); public void ejbActivate() throws EJBException, RemoteException {} public void ejbLoad() throws EJBException, RemoteException {} public void ejbPassivate() throws EJBException, RemoteException {} public void ejbRemove() throws RemoveException, EJBException, RemoteException {} public void ejbStore() throws EJBException, RemoteException {} public void unsetEntityContext() throws EJBException, RemoteException { this.ctx = null; } public void setEntityContext(EntityContext arg0) throws EJBException, RemoteException { this.ctx = arg0; } public String ejbCreate(String productID,String name,String desc,double basePrice)throws CreateException{ setProductID(productID); setDescription(desc); setName(name); setBasePrice(basePrice); return productID; } Programmazione su Reti 2 2004/2005 Pagina 32 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 public void ejbPostCreate(String productID,String name,String desc,double basePrice){} } La classe ProductBean è astratta ed anche i suoi metodi accessori sono astratti, il container a deployment time renderà concreta la classe implementando i metodi accessori, i quali conterranno la logica per la persistenza dei dati. Oltre ai metodi che già si trovano nell’interfaccia EntityBean, implementiamo il metodo ejbCreate e il corrispondente ejbPostCreate6. Da notare che l’ejbCreate ritorna una stringa (il productID), mentre il metodo Create dell’home ritornava un ProductLocal, perché il container utilizza la chiave primaria come riferimento agli oggetti. Una volta compilato si crea il file jar dove s’inserisce il file ejb-jar.xml che conterrà inoltre la query per il metodo findAll, mentre per la findByprimaryKey il container sa come implementarla. Di seguito riportiamo parte del file xml: <enterprise-beans> <entity> <ejb-name>ProductBean</ejb-name> <local-home>ProductLocalHome</local-home> <local>ProductLocal</local> <ejb-class>ProductBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>java.lang.String</prim-key-class> <reentrant>false</reentrant> <cmp-version>2.x</cmp-version> <abstract-schema-name>ProductBean</abstract-schema-name> <cmp-field> <description xml:lang="it">no description</description> <field-name>basePrice</field-name> </cmp-field> <cmp-field> <description xml:lang="it">no description</description> <field-name>productID</field-name> </cmp-field> <cmp-field> <description xml:lang="it">no description</description> <field-name>description</field-name> </cmp-field> <cmp-field> <description xml:lang="it">no description</description> <field-name>name</field-name> </cmp-field> <primkey-field>productID</primkey-field> <security-identity> <use-caller-identity/> </security-identity> <query> 6 Utilizzato per eventuali elaborazioni dei dati dopo la creazione di un prodotto. Programmazione su Reti 2 2004/2005 Pagina 33 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 <query-method> <method-name>findAll</method-name> <method-params/> </query-method> <ejb-ql>SELECT OBJECT(a)ProductBean AS aa.productID IS NOT NULL</ejb-ql> </query> </entity> </enterprise-beans> 6.3.2 Session Stateless: SkatesProducts I metodi di business saranno forniti dal session bean SkatesProducts che implementerà tre metodi per le tre operazioni richieste. SkatesProducts interagirà con il bean Product potendo così creare ed effettuare ricerche sui prodotti memorizzati. Si forniranno soltanto interfacce remote visto che in locale non sarà utilizzato da nessun altro bean. Riportiamo di seguito il codice dell’interfaccia home e dell’oggetto remoto: SkatesProducts.java import java.rmi.RemoteException; import javax.ejb.EJBObject; public interface SkatesProducts extends EJBObject { public void addProduct(String pID,String name,String descr, double price)throws RemoteException; public double getPriceOfProduct(String pID)throws RemoteException; public String getAllProducts()throws RemoteException; } SkatesProductsHome.java import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EJBHome; public interface SkatesProductsHome extends EJBHome { public SkatesProducts create() throws RemoteException,CreateException; } Nell’interfaccia dell’oggetto remoto sono stati messi i tre metodi richiesti per il sistema, da notare che il metodo getAllProducts restituisce una stringa, semplicemente per ovviare al problema del passaggio di tipi complessi che non erano stati ancora affrontati nel corso di programmazione su reti. L’interfaccia home espone il solito metodo per la creazione di un oggetto di tipo SkatesProducts. Vediamo ora il codice d’implementazione del bean: Programmazione su Reti 2 2004/2005 Pagina 34 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 SkatesProductsBean.java import java.rmi.RemoteException; import java.util.Iterator; import javax.ejb.CreateException; import javax.ejb.EJBException; import javax.ejb.FinderException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; import javax.naming.InitialContext; import javax.rmi.PortableRemoteObject; public class SkatesProductsBean implements SessionBean { private SessionContext ctx; public void ejbCreate() throws EJBException{} public void addProduct(String pID,String name,String descr, double price){ ProductLocalHome homeEntity = null; try{ InitialContext ic = new InitialContext(); Object obj = ic.lookup("java:comp/env/ejb/Product"); homeEntity = (ProductLocalHome)PortableRemoteObject.narrow(obj,ProductLocalHome.class); }catch(Exception e){ System.out.println("Errore nella addProduct: nella ricerca dell'entity bean."); } try { homeEntity.create(pID,name,descr,price); } catch (CreateException e1) { System.out.println("Errore nella addProduct: nella creazione dell'entity bean."); } } public double getPriceOfProduct(String pID){ ProductLocalHome homeEntity = null; try{ InitialContext ic = new InitialContext(); Object obj = ic.lookup("java:comp/env/ejb/Product"); homeEntity = (ProductLocalHome)PortableRemoteObject.narrow(obj,ProductLocalHome.class); }catch(Exception e){ System.out.println("Errore nella getPriceOfProduct: nella ricerca dell'entity bean."); } ProductLocal entity = null; try { entity = homeEntity.findByPrimaryKey(pID); } catch (FinderException e1) { System.out.println("Errore nella getPriceOfProduct: entity non trovato."); Programmazione su Reti 2 2004/2005 Pagina 35 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 } if(entity!=null){ return entity.getBasePrice(); }else{ System.out.println("Errore nella getPriceOfProduct: alla getBasePrice."); } return -1; } public String getAllProducts(){ ProductLocalHome homeEntity = null; try{ InitialContext ic = new InitialContext(); Object obj = ic.lookup("java:comp/env/ejb/Product"); homeEntity = (ProductLocalHome)PortableRemoteObject.narrow(obj,ProductLocalHome.class); }catch(Exception e){ System.out.println("Errore nella getAllProducts: nella ricerca dell'entity bean."); } ProductLocal entity = null; Iterator i = null; String str = ""; try { i = homeEntity.findAll().iterator(); } catch (FinderException e1) { System.out.println("Errore nella getAllProducts: entity non trovato."); } while(i.hasNext()){ entity = (ProductLocal)PortableRemoteObject.narrow(i.next(),ProductLocal.class); str += entity.getProductID()+" "+entity.getName()+" "+entity.getDescription()+" "+entity.getBasePrice()+"\n"; } return str; } public void ejbActivate() throws EJBException, RemoteException {} public void ejbPassivate() throws EJBException, RemoteException {} public void ejbRemove() throws EJBException, RemoteException {} public void setSessionContext(SessionContext arg0) throws EJBException, RemoteException { this.ctx = arg0; } } Nell’implementazione del bean troviamo i tre metodi prima descritti. In tutti e tre si cerca il riferimento all’entity bean Product tramite il riference ejb/Product il quale sarà specificato nel file di descrizione ejb-jar.xml. poi a questo punto ogni metodo richiama un metodo di Product a Programmazione su Reti 2 2004/2005 Pagina 36 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 seconda della logica da implementare. Dopo aver compilato il tutto si creerà il file punto jar dove oltre alle classi compilate s’inserirà il file xml di deployment che qui di seguito se ne riporta una parte. <enterprise-beans> <session> <ejb-name>SkatesProductsBean</ejb-name> <home>SkatesProductsHome</home> <remote>SkatesProducts</remote> <ejb-class>SkatesProductsBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Bean</transaction-type> <ejb-local-ref> <ejb-ref-name>ejb/Product</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <local-home>ProductLocalHome</local-home> <local>ProductLocal</local> <ejb-link>Product.jar#ProductBean</ejb-link> </ejb-local-ref> <security-identity> <use-caller-identity/> </security-identity> </session> </enterprise-beans> Reference a Product 6.3.3 Skatestown.ear In fine per creare un unico file di deployment si uniscono i due file jar fin ora prodotti, uno per Product e l’altro per SkatesProducts, in un unico file con estensione ear7 inserendovi un file di descrizione chiamato application.xml: <?xml version="1.0" encoding="UTF-8"?> <application xmlns="http://java.sun.com/xml/ns/j2ee" version="1.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd"> <description xml:lang="it">Application description</description> <display-name xml:lang="it">Skatestown</display-name> <module> <ejb>Product.jar</ejb> </module> <module> <ejb>SkatesProducts.jar</ejb> </module> </application> A questo punto bisogna fare il deployment sul container, ma prima di effettuarlo bisogna 7 Un file ear è anchesso un file zippato come i file jar, utilizzato per mettere insieme più componenti di un progetto sviluppato in J2EE. Programmazione su Reti 2 2004/2005 Pagina 37 di 38 Enterprise Java Beans e Web Services Data:20/05/2005 costruire un riferimento ad un database dove si memorizzeranno i prodotti. Nel nostro esempio utilizzando AS 8.0 si dovrà creare uno JDBC Resources di nome jdbc/Product con l'admin console della distribuzione, il riferimento sarà di tipo PointBasePool8. Dopo aver fatto il deployment sul container ci facciamo restituire il jar per il client e scriviamo il file wsdd per Axis. È importante mettere il client jar che vi fate generare con il deploytool, nella cartella {TomcatHome}\webapps\axis\WEB-INF\lib prima di effettuare il deployment con Adminclient. Ricordatevi che per abilitare Axis all'uso degli ejb mettete j2ee.jar sotto la cartella {TomcatHome}\common\lib. Per quanto riguarda il client basta eseguirlo con i jar di Axis. Tutto il materiale citato si trova in allegato alla presente relazione. 8 Utilizziamo l’ODB della distribbuzione della Sun Programmazione su Reti 2 2004/2005 Pagina 38 di 38