MokaByte Numero  41  - Maggio 2000
 
Enterprise Java Beans
di 
Giovanni Puliti
Una panoramica introduttiva a questi nuovi componenti che sembra rivoluzioneranno il modo di creare applicazioni distribuite

Il nuovo modello di object distribuited computing presentato da Sun si chiama Enterprise Java Beans, e promette una semplificazione incredibile rispetto a quanto disponibile fino ad ora in tale settore

Introduzione
Presentati ufficialmente poco più di un anno fa da Sun, gli Enterprise Java Beans (EJB) stanno risquotendo un successo a dir poco incredibile. Oltre ad essere sulla bocca di tutti i vari Java-guru, o nei numerosi comunicati stampa, è altresì vero che la maggior parte delle aziende ha da tempo dirottato una parte congrua delle proprie energie per produrre server  per EJB, oppure tecnologia di vario tipo che si interfacci con tali componenti.
Dovendo fare una panoramica completa ed esaustiva sull’argomento sarebbe necessario molto più spazio di quello a disposizione, sia per la vastità dei temi che per la complessità di certi passaggi. Cercheremo quindi di dare una visione il più possibile esaustiva, dell’argomento, rimandando per gli approfondimenti a [1] e [2]. 
Come spesso accade nel mondo Java, l’argomento per quanto interessate non è in fin dei conti niente di radicalmente innovativo, basandosi su concetti ormai ben noti, anche se la visione “alla Java” ne conferisce aspetti decisamente interessanti.
Da un punto di vista architetturale EJB non è che un altro modo di vedere e di implementare il modello della computazione distribuita, della quale nel corso degli anni si sono viste numerose variazioni sul tema. 


Figura 1: il logo  di EJB

Fra le molte soluzioni proposte negli ultimi tempi, una delle più famose è quella basata sugli oggetti distribuiti, i quali possono essere eseguiti in remoto e su più macchine indipendenti fra loro. 
Questo settore però già prima degli EJB offriva importanti alternative: da un lato  infatti la Remote Method Invocation (RMI, vedi [3]) introdotta con il JDK 1.1 permette in maniera piuttosto semplice la realizzazione di architetture distribuite full-Java ed è di fatto la soluzione più semplice disponibile fino alla comparsa di EJB. Parallelamente troviamo CORBA, attualmente il più versatile, eterogeneo, potente ma anche complesso sistema di gestione degli oggetti remoti e distribuiti (non prenderemo in considerazione MTS di Microsoft che non può essere preso come esempio di tecnologia distribuita, visto che limita il suo utilizzo alla piattaforma Windows).
Verrebbe da chiedersi quindi a cosa possa servire un nuovo modello di oggetti distribuiti, oppure cosa introduca di nuovo rispetto a quanto disponibile sul mercato. 
Ebbene la differenze fondamentale è data dal supporto dato per la realizzazione applicazione distribuite. RMI e CORBA infatti sono semplicemente dei motori di oggetti distribuiti (solo Java nel primo caso, language-neutral nel secondo), ed i cosiddetti ditribuited object services devono essere implementati a mano o forniti per mezzo di software terze parti. Nel modello degli EJB invece tutto quello che riguarda la gestione dei servizi è disponibile e, cosa ancora più importante, utilizzabile in maniera del tutto automatica  e trasparente agli occhi del client. 
Per servizi si intende in genere tutte quelle funzionalità atte alla implementazione dei seguenti aspetti:
 

  • Transazioni: le transazioni sono un insieme di operazioni che devono essere svolte in maniera atomica, oppure fallire totalmente. La modalità transazionale è particolarmente importante nel mondo del commercio elettronico, e nella maggior parte delle casistiche reali. I container EJB offrono un sistema automatico per la gestione delle transazioni.
  • Security: quando si ha a che fare con modelli distribuiti, la gestione della sicurezza è uno degli aspetti più importanti. Nel modello EJB viene fornito il supporto offerto dal modello della security della piattaforma Java 2.
  • Scalabilità: la filosofia con cui EJB è  stato progettato, e soprattutto la modalità con cui opera, permette la massima flessibilità e scalabilità in funzione del traffico dati e del numero di clienti (ad esempio quali, quanti e come i vari bean vengano forniti ai vari client è un meccanismo gestito automaticamente dal server).
Da notare che EJB si “appoggia” ad RMI del quale utilizza le funzionalità e la filosofia di base per realizzare strutture distribuite, estendendone come visto i servizi in maniera trasparente.
La specifica di EJB definisce una architettura  standard per l’implementazione della business logic in applicazioni multi-tier  basate su componenti riusabili. Tale architettura è basata essenzialmente su tre componenti: i server, i container ed i client.
Il server EJB  ha lo scopo di incapsulare tutto quello che sta sotto lo strato EJB (applicazioni legacy, servizi distribuiti) e di fornire ai contenitori una serie di servizi di base per i vari componenti installati.
Il contenitore invece è stato progettato per offrire una serie di funzionalità legate al life-cycle dei vari componenti, la gestione delle transazioni, e il security-management. Grazie all’intercettazione delle chiamate dei metodi effettuate dai vari clienti, il contenitore è in grado di  gestire le transazioni che si instaurano fra chiamate successive, relativamente a contenitori differenti e server in esecuzione su macchine diverse. Lo sviluppatore di un componente EJB può quindi concentrarsi sui dettagli implementativi della business logic, tralasciando gli aspetti legati alla gestione, dato che sono a carico del contenitore. L’unica cosa che deve fare chi sviluppa un componente è implementare una serie di interfacce standard. Il client infine rappresenta l’utilizzatore finale del componente. La visione che ha del componente è resa possibile grazie a due interfacce (Home interface e Remote interface), la cui implementazione è effettuata automaticamente dal container al momento del deploy del bean stesso. La Home interface fornisce i metodi relativi alla creazione del bean, mentre l’altra implementa la  business logic. Implementando queste due interfacce ed i loro relativi metodi, il container è in grado di intercettare le chiamate provenienti dal client, ed al contempo fornendogli una visione semplificata del componente stesso. Il client non ha la  percezione di questa interazione da parte del container: 
il vantaggio è quindi quello di offrire in modo indolore, la massima flessibilità, scalabilità oltre ad una non indifferenze semplificazione del lavoro da svolgere.


 
 
 

Tipologie di EJB
Due sono i tipi di Enterprise Java Beans: i session beans e gli entity bean. Il primo tipo rappresenta un collegamento con il client e soprattutto l’interazione con esso; rappresenta una estensione logica del programma client. 
In genere i bean di questo tipo implementano una sequenza di operazioni all’interno di una transazione.
Gli entity beans invece rappresentano dati specifici o collezioni di dati.  In genere forniscono metodi per l’interazione con i dati che essi stessi rappresentano. Questo tipo di componenti sono persistenti, dato che restano in vita per tutto il tempo che sono memorizzati all’interno del db. 
 
 
 

I Session Beans
Ci sono due tipi di entity beans: stateless  e stateful. Il primo tipo non mantiene nessun tipo di informazione fra due invocazioni dei suoi metodi da parte del client, e per ciò questo tipo di bean è in genere utilizzato per eseguire operazioni atomiche, indipendenti dal contesto nel quale vivono. 
Sono detti beans “amorfi” dato che le varie  istanze dello stesso  bean sono del tutto equivalenti fra loro, e di fatti per ottimizzare le prestazioni, alcuni server  istanziano un set di bean stateless implementando una gestione a pool.
Fra tutti i tipi di beans, questi sono i più semplici, leggeri e facili da utilizzare. L’altro tipo invece, i bean stateful, sono in grado di memorizzare uno stato fra due invocazioni del client, permettendo fra le altre cose una politica di gestione delle transazioni. 
Ogni bean di questo tipo è associato ad uno ed un solo client. Tipicamente la gestione dello stato viene effettuata automaticamente dalla coppia  server-container, quindi riducendo drasticamente il lavoro che si deve svolgere in fase di sviluppo sia del client che del bean stesso.
E’ da notare tuttavia che i session beans non sono stati progettati per essere persistenti, né  gli stateful  né gli stateless: i dati che infatti essi memorizzano sono intesi relativamente ad una particolare sessione o client. E’ per questo motivo che un session beans non può sopravvivere a crash di sistema o semplici restart del server; infatti il cosiddetto handle del bean, riferimento creato all’interno del container per accedere a quel particolare bean, viene perso nel momento in cui il client muore o la sessione finisce.
Nel caso in cui il client necessiti di riutilizzare un bean rimosso, deve utilizzare le informazioni in suo possesso (sul lato client) per poter ricreare il componente sul server.
 
 
 

Gli Entity Beans
Si è  detto che un Entity  è un bean progettato per la rappresentazione  di strutture dati  nel server, strutture dati messe a disposizione per elaborazioni particolari o per l’utilizzo da parte del client. E’ quindi importante, così come nel caso dei session bean, offrire verso l’esterno una interfaccia che permetta di utilizzare tali componenti: tale interfaccia si ottiene implementando le due solite (la Home e la Remote) più una terza, la EntityBean.
Oltre a tutto ciò, devono essere sviluppati metodi per la ricerca del componente da parte del client: quello più importate che deve essere necessariamente riscritto è il findByPrimaryKey(), il quale necessita al suo fianco della creazione di una chiave primaria (classe PrimaryKey) per consentire l’identificazione unica e serializzabile del bean.
Al fine di implementare la persistenza del componente, devono essere specificate quali variabili dovranno essere rese persistenti per mezzo di salvataggio in un db di qualche tipo.
Questa funzionalità prevede due modalità di base: la container-managed persistence e la  bean-managed persistence. 
Nel primo caso tramite meccanismi automatici del server le informazioni sono memorizzate in una struttura d’appoggio come ad esempio un RDBMS, mente nell’altro tipo di bean tale compito è totalmente a carico dell’implementazione  del bean. 
Per creare un Entity Bean,  si può operare in due modi: per mezzo dell’azione diretta del client, il quale può invocare i metodi di creazione della Home Interface, o in alternativa effettuando una qualche operazione che aggiunga nel database dati che rappresentino il bean. 
Per avere un riferimento di un componente già esistente invece, il client può operare in diversi modi: ricevere il bean come parametro di una invocazione di metodi remoti, effettuare una ricerca presso il server per mezzo dei metodi di ricerca, ottenere dinamicamente un handle dal container il quale provvede a fornire il bean più indicato.
 
 
 

Il ruolo del server 
Il server per i bean è l’elemento fondamentale di tutta la piattaforma EJB: questo componente infatti svolge buona parte del lavoro necessario sia per rendere un componente utilizzabile dai vari client remoti, sia per supportare i servizi più importanti (transazioni, mantenimento dello stato, sessioni, sicurezza) associati ai vari bean. 
Molti sono i server disponibili attualmente sul mercato: dato infatti che EJB non è un prodotto ma una specifica, i vari produttori sono liberi di realizzare la loro implementazione compatibile con la versione 1.0 o 1.1 delle specifiche rilasciate da Sun (la 2.0 è attesa per quest’anno). 
Da questo punto di vista lo scenario è piuttosto articolato, e non si ha che l’imbarazzo della scelta. Le persone con le quali ho avuto modo di scambiare un po’ di impressioni, mi hanno confermato che non esiste il prodotti ideale, o quello da scartare a priori (a parte certi casi  estremi), dato che la scelta dipende molto dalla situazione particolare. 
Per sapere quali siano attualmente i prodotti disponibili sul mercato rilasciati dalle diverse case si veda il riquadro “EJB Application Server”.
Come accennato poco sopra, il processo di creazione di un bean, e di deploy nel server passa per la definizione di alcune interfacce in modo che il server possa gestire il componente. In particolare, le interfacce da estendere sono

  • Home interface: basata sul pattern factory ([5] e [6]) fornisce i metodi per creare un’istanza del componente
  • Remote interface: definisce i metodi del bean stesso
  • La bean implementation class invece implementa l’interfaccia remota, fornisce di fatto il corpo del bean stesso e ne definisce il comportamento.


La cosa estremamente interessante è che non è necessario fornire l’implementazione delle due prime interfacce, compito svolto automaticamente dal server.
Per poter completare con successo la fase di deploy del bean nel server è necessario inoltre fornire i cosiddetti deployment descriptors, operazione effettuabile al momento del deploy del componente utilizzando il tool fornito dal server.


Figura 2 Modalità di operativa  degli EJB: si noti come gli oggetti remoti non sono messi a disposizione direttamente dal server, ma il client interagisce con questi tramite una serie di interfacce remote; il meccanismo è molto simile a quello offerto da RMI.


 



Creazione di un bean
Contrariamente all’utilizzo, il processo di creazione di un bean è piuttosto complesso dal punto di vista teorico, anche se il codice da scrivere è di fatto piuttosto semplice. Per brevità vedremo come realizzare un entity bean, rimandando alla bibliografia l’altro caso che prenderebbe effettivamente troppo spazio.
Dato che EJB è una tecnologia definita da Sun di livello Enterprise (Java 2 Enterprise Edition – J2EE), per poter sviluppare un bean ed effettuare le prime prove non è sufficiente installare il solo JDK 1.2, ma si devono  scaricare i packages opportuni (javax.ejb), e settare il classpath in modo opportuno. 
La prima cosa da fare quindi è importare all’interno del proprio codice i packages necessari per far funzionare il tutto
 

import java.rmi.RemoteException; 
import javax.ejb.*;


Si noti come oltre a javax.ejb, si fa riferimento anche a RMI,  dato che esso rappresenta il motore utilizzato per la gestione degli oggetti remoti.
Si può passare quindi a realizzare il bean: si supponga ad esempio di voler mappare il concetto di articolo pubblicato su una delle riviste del Gruppo Editoriale  Infomedia con un bean. In tal caso sarà necessario per prima cosa definire una interfaccia idonea, come ad esempio

public interface Article extends EJBObject{
public String getTitle() throws RemoteException; 
      public String getAuthor() throws RemoteException; 
}
Poiché tali oggetti vivono in un contesto distribuito, ogni metodo deve poter propagare (per mezzo di throws) la RemoteException, dato che qualcosa di non previsto può sempre accadere.
La home interface svolge la funzione di factory e per questo mette a disposizione i metodi per la creazione del bean
 
public interface ArticleHome extends EJBHome { 
     public Article create() throws CreateException, RemoteException; 
}


In questo caso si è provveduto a fornire un solo metodo per la creazione del bean, ma ne potevano essere presenti altri che ricevevano come parametri ad esempio il titolo o altro valore.
Infine la classe che implementa l’interfaccia remota rappresenta il bean stesso

public class ArticleBean  implements SessionBean 

Il metodo per la creazione del bean di fatto istanzia la variabile relativa al titolo dell’articolo

  public void ejbCreate() { 
    Title = "EJB in pratica”; 
  } 

In questo caso abbiamo una versione molto semplificata dell’oggetto remoto, versione che svolge offre solo alcune funzionalità. Inoltre tale classe espone  i seguenti metodi per la manipolazione delle variabili

  public String getTitle() throws EJBException{ 
     return Title;
  } 
  
  public String getAuthor() throws EJBException{ 
     return Author;
  }

Infine da notare la presenza dei metodi 

public void ejbActivate(){} 
public void ejbPassivate(){} 
public void ejbRemove(){} 
public void setSessionContext(SessionContext context){} 

che servono per la gestione del ciclo di vita del bean : gli aspetti legati a questo argomento sono piuttosto complessi e di fatto non basterebbe un articolo intero per esaminarli tutti. 
Diciamo per brevità che un bean vive una sua vita che per certi versi può essere paragonata a quella di un thread nella JVM o ad un processo in un sistema operativo multitasking. Ad esempio per motivi di performance un container può decidere di serializzare su file un componente non utilizzato da un po’ di tempo: quando ciò accade il bean ne riceve notifica per mezzo di una chiamata a  ejbPassivate(). All’interno di tale metodo quindi possiamo scrivere tutte le istruzioni necessarie per rilasciare le risorse non utilizzate come ad esempio  connessioni di rete  o altro. 
Quando un bean è richiesto nuovamente, una chiamata a ejbActivate() effettuerà le operazioni necessarie per risvegliare il bean, come ad esempio la riapertura della connessione di rete.
Quando infine un bean è rimosso dal container viene effettuata una chiamata al metodo ejbRemove().
Il metodo setSessionContext() viene in genere invocato per dare al bean la possibilità di gestire le transazione e la security in una sessione.
Dato che tali metodi sono chiamati in automatico in funzione del ciclo di vita del componente, analizzando  il loro significato già si può intuire la potenza del modello EJB. Si pensi ad esempio al caso della connessione di rete: essa verrà aperta o chiusa automaticamente in funzione dello scheduling che il server EJB effettua sul componente.
Dopo la parte implementativa del bean, si deve provvedere al deploy all’interno del server: questa operazione in genere è effettuata grazie all’utilizzo dei vari tool e wizard forniti di corredo con il server utilizzato. Per maggiori approfondimenti su tali aspetti si può ricorrere di fatto alla documentazione del prodotto scelto.
 
 
 

Usare un EJB dal client
Una volta che il bean è pronto per essere utilizzato, il lavoro da fare da parte del client è piuttosto semplice.  Di fatto si devono effettuare queste tre operazioni

  • utilizzare il nome del bean per localizzare l’interfaccia home
  • utilizzare l’interfaccia home per creare una istanza del bean
  • utilizzare direttamente il bean invocandone i metodi che mette a disposizione


La localizzazione avviene individuando da qualche parte la home interface, compito che viene svolto per mezzo della classe java.naming.Context. L’interfaccia remota viene localizzata per mezzo della JNDI  API utilizzando il nome “ArticleJNDI”  utilizzato al momento del deploy del bean nel server EJB.

   Context initial = new InitialContext(); 
   Object o = initial.lookup("ArticleJNDI"); 

Una volta ottenuta l’interfaccia remota si utilizza  la classe  PortableRemoteObject  per effettuare una conversione nel tipo voluto. 

ArticleHome home;
home=(ArticleHome)PortableRemoteObject.narrow(o, ArticleHome.class); 

Infine per mezzo del metodo create() si crea l’istanza dell’oggetto ed utilizzarne i metodi ad esempio per ricavarne le informazioni memorizzate.

Article art = home.create(); 
System.out.println(art.getTitle());
Una volta che il bean non serve più, è bene rimuoverlo dal container in modo da rilasciare le risorse allocate
art.remove(); 

 
 
 

Conclusione
Dopo questa veloce panoramica sui componenti EJB, si possono fare due osservazioni. 
La prima è come si pone EJB nei confronti delle tecnologie già presenti sullo scenario della computazione distribuita. 
Si è detto a tal proposito che i concorrenti sono essenzialmente due, ovvero RMI e CORBA (più MTS che però corre per una strada tutta sua).
Il primo di fatto rappresenta il motore che permette tutto il funzionamento della tecnologia EJB, e quindi non si pone in concorrenza con EJB, ma semmai in aiuto. 
Si deve dire che la scelta fra le due soluzioni (solo RMI o EJB), deve essere fatta in funzione della tipo di applicazione che si deve realizzare. Nel caso infatti di sistemi semplici, fortemente dipendenti dal caso particolare, forse il semplice utilizzo di RMI può essere sufficiente; nel caso di situazioni complesse dove è necessaria la massima flessibilità e scalabilità (vedi e-commerce o JSP) allora la soluzione EJB è la migliore.
CORBA invece vede le cose da un altro aspetto: più potente e più complesso sia di RMI che di EJB, non offre a tutt’ora (a meno di utilizzare implementazioni proprietarie come VisiBroker)  il supporto per i servizi distribuiti, vero punto di forza di EJB. 
CORBA offre però prestazioni migliori (è risaputo che RMI non sia un campione di velocità), e la possibilità di interagire con sistemi e tecnologie differenti (vedi legacy).
La seconda considerazione da fare è quando e dove EJB debba essere utilizzato, e per svolgere quale tipo di compiti.
La risposta è molto semplice: in tutti quei casi in cui si debbano  realizzare applicazioni multistrato distribuite, basate su oggetti mobili.
Al momento il paradigma più utilizzato è quello del 3Tier, modello che non necessariamente si deve appoggiare a modelli di oggetti distribuiti, ma è anche vero che quest’ultimo sta prendendo piede ad una velocità sempre maggiore. Java da questo punto di vista è la soluzione (l’unica) in grado di fornire massima flessibilità e potenza implementativa,  ed è per questo che sta risquotendo un sempre maggiore successo in questo settore.
 
 

Bibliografia
[1] –  “Enterprise Java Beans” – di Richard  Monson Haefel, Ed. O’Reilly
[2] – “Professional Java Server programming” – aa.vv. Ed Wrox
[3] – “Remote Method Invocation” di Giovanni Puliti, MokaByte 16 – www.mokabyte.it/0298
[4] – “Introduction to CORBA” http://developer.java.sun.com/developer/onlineTraining/corba/magecontents.html
[5] – “Design Patterns” – di Gamma Helm Johnson, Vlissides – Ed. Addison Wesley
[6] – “Il pattern factory” di L. Bettini, A. Trentini - MokaByte 27 – www.mokabyte.it/2099
 
 
 
 

Appendice A:  EJB Application Server e case produttrici
 
Azienda produttrice
Nome del prodotto
BEA System
Bea Web Logic Server/Enterprise
BlueStone Software
Sapphire/Web
BROKAT Infosystems
Brokat Twister
Fujitsu Software
Interstage
GemStone Systems
GemStone/J
Haht Software
HAHT site Application Server
IBM
WebSphere Application Server
Component Broker
CICS Transaction Server 
TXSeries
Information Builders
Parlay Application Server
Inprise
Inprise Application Server
Iona Tech.
Orbix Enterprise
Netscape Comm.
Netscape Application Server
Novera Software
JBusiness
Object Space
Voyager
Oracle
Oracle Application Server
Persistence Software
Power Tier for EJB
Secant Tech.
Secant Extreme Enterprise Server
Siemens
Siemens Enterprise Application Server
Silver Stream
SilverStream Application Server
Sun Microsystems
NetDynamics Application Server
Sybase
Sybase Enterprise Application Server
Valto Systems
Ejipt
Visient
Arabica
Chi volesse mettersi in contatto con la redazione può farlo scrivendo a mokainfo@mokabyte.it