MokaByte 48 - Gennaio 2001
Foto dell'autore non disponibile
di
Raffaele Spazzoli
EJB’s Design Techniques
I Parte
Questo è il primo di due articoli che presentano una raccolta delle tecniche più comunemente usate dalla comunità dei programmatori di Enterprise Java Beans per trarre il massimo vantaggio dal framework degli EJB.
Gli Enterprise Java Beans (EJB) nascono come risposta al bisogno sempre crescente di potere sviluppare in tempi estremamente rapidi applicazioni lato server. Gli EJB rappresentano la tecnologia ideale per sviluppare applicazioni a tre livelli, essi possono essere visti come componenti lato server il cui ciclo di vita è controllato da un software di middleware detto EJB Container. I compiti del container non si fermano qui, infatti il container implementa alcune funzionalità di framework comuni a tutte le applicazioni lato server quali ad esempio il controllo sulla persistenza dei dati, la gestione delle transazioni, la gestione della sicurezza a livello applicativo… L’obiettivo quindi del framework, implementato dal container, è quello di sollevare lo sviluppatore da tutta una serie di problematiche comuni alla maggior parte delle applicazioni distribuite ed in gran parte indipendenti dal dominio del problema dell’applicazione, lasciando quindi più tempo al programmatore per risolvere problemi legati alla logica di business della applicazione che sta sviluppando.
Nonostante questo il programmatore non può ignorare le caratteristiche del framework in cui opera se non vuole scontrarsi con alcune insidie che gli EJB presentano. L’obiettivo di questa raccolta di EJB’s design technique è proprio quello di evidenziare alcuni problemi degli EJB e di presentare le migliori soluzioni fino ad ora scoperte dalla comunità dei programmatori EJB. 
Il lettore di questo documento dovrebbe avere una discreta conoscenza della tecnologia degli EJB[1] e delle problematiche delle applicazioni distribuite[2]. 
Nel web è possibile incontrare queste tecniche indicate col nome di pattern, in realtà con pattern a mio parere si intende qualcosa di molto generico, indipendente dal particolare linguaggio o dal particolare framework. Mentre alcune delle tecniche che vedremo sono effettivamente una applicazione all’architettura degli EJB di pattern già noti, altre invece sono semplici workaround a problemi connaturati all’architettura degli EJB. 
 
 
 

Tecniche Comuni a tutti gli EJB
Le tecniche che seguono sono adatte ad entrambi i tipi di EJB: Session Bean ed Entity Bean.

Business Interface

Nome: Business Interface.

Problema: in fase di sviluppo è difficile mantenere sincronizzate la remote interface di un Bean e la sua implementazione perché i controlli avvengono solo in fase di deploy.

Relazioni con altre tecniche: assieme al Business Object assicura la separazione (anche a livello di package) fra la Business Logic e la logica legata alla tecnologia (EJB in questo caso).

Descrizione: secondo le specifiche degli EJB i metodi di Business Logic definiti da un EJB che si vuole siano visibili ai Client devono essere esposti nella RemoteInterface del Bean. Tali metodi devono poi essere effettivamente implementati nella classe che definisce il Bean. L’unica cosa che distingue le signature dei metodi della RemoteInterface da quelli del Bean è che quelli della RemoteInterface devono necessariamente contenere java.rmi.RemoteException fra le eccezioni sollevate. Sorge dunque il problema di mantenere sincronizzate la RemoteInterface e la implementazione del Bean.
Teoricamente il Bean può implementare la propria RemoteInterface, ma questo risulta sconveniente in quanto costringe (vedi [1]) il programmatore a dare una implementazione vuota ai metodi di javax.ejb.EJBObject da cui tutte le RemoteInterface devono estendere.
Eventuali incongruenze fra la RemoteInterface e l’implementazione del Bean, vengono rilevate solo in fase di deploy dal container; questa non è proprio la situazione ideale poiché il bean provider (colui che implementa il bean) e il bean deployer (colui che esegue il deploy [1]) sono due figure distinte e non necessariamente il deployer è una persona dotata di skill di programmazione. 
Per mantenere sempre sincronizzati la RemoteInterface con i metodi del Bean si può usare la tecnica chiamata Business Interface che definisce una interfaccia detta appunto Business Interface nella quale si definiscono tutti i metodi di business logic del Bean. Poi si fa implementare tale interfaccia al Bean e la si fa estendere alla RemoteInterface. Supponendo di avere un Bean con un solo metodo di business logic (doBusiness) la situazione sarebbe questa:
Business Interface:

public interface BusinessInterface {
    public void doBusiness() throws java.rmi.RemoteException;

Remote Interface:

public interface BusinessRemote extends BusinessInterface, javax.ejb.EJBObject {
}
 

Bean:

public class BusinessBean implements javax.ejb.XXXBean, BusinessInterface {
    public BusinessBean() {
    }
    public void doBusiness() throws java.rmi.RemoteException {
    }
    …. Container oriented methods … 
}

Dove XXXBean può essere EntityBean o SessionBean.
L’unico svantaggio di tale approccio è che si costretti a dichiarare che tutti i business methods sollevano la java.rmi.RemoteException (perché ciò è richiesto nella RemoteInterface), anche se ciò generalmente non è vero. Infatti un business method dovrebbe dichiarare solo eccezioni dovute a logica di business e segnalare tutti gli altri problemi tramite una javax.ejb.EJBException o un’altra runtime exception. Notiamo che questa tecnica non risolve tutti i problemi di sincronia che nascono usando gli EJB. Infatti la sincronia fra la HomeInterface (metodi di create e find) e il bean non può essere mantenuta con una superinterface comune perché i metodi da tenere sincronizzati hanno un nome diverso. Fortunatamente essendo questi factory methods dovrebbero variare meno frequentemente durante la fase di sviluppo.
 
 

Business Object

Nome: Business Object.

Problema: l’architettura EJB porta il programmatore a mescolare business logic e logica legata solamente alla tecnologia usata (EJB) rendendo difficile il porting di progetti in e out da questo framework.

Relazioni con altre tecniche: assieme al Business Interface assicura la separazione (anche a livello di package) fra la Business Logic e la logica legata alla tecnologia (EJB in questo caso).

Descrizione: quando il Bean Provider implementa un Bean deve dare implementazione, oltre a tutti i Business Methods, anche ad un certo numero di metodi “di framework”. Questi metodi che variano in base al tipo di Bean servono al container per gestire il ciclo di vita del Bean.
Avere Business Methods e metodi tecnologici (container oriented in questo caso) nella stessa classe può limitare la portabilità dell’applicazione ad altre tecnologie. In generale comunque è buona norma tenere separata la business logic da tutte le classi, framework e package di appoggio il cui unico scopo è quello di rendere gli oggetti di business logic fruibili dai client del sistema.
A tal fine si può spingere la tecnica vista per la Business Interface un passo più avanti implementando i metodi di business in un oggetto che non sia il Bean, ma che poi il Bean estenderà. 
Il fatto di avere isolato la businnes logic dalla logica legata alla tecnologia fa sì che ora nel Bean si implementino solo i metodi container oriented: quelli di factory o dedicati alla persistenza del Bean. 
Adottando questa tecnica il codice sopra mostrato si modifica nel seguente modo:

BusinessObject:

public class BusinessObject implements BusinessInterface {
    public BusinessObject() {
    }
    public void doBusiness() throws java.rmi.RemoteException {
    }
}

BusinessBean:

public class BusinessBean extends BusinessObject implements javax.ejb.SessionBean {
    public BusinessBean() {
    } 
    … Container oriented methods … 
}
 
 
 

Entity Beans
Gli Entity Bean sono un tipo di Enterprise Java Bean. Essi rappresentano entità persistenti del sistema. Gli Entity Bean hanno due tipi di problemi. Per prima cosa le specifiche degli EJB li propongono come business object del sistema. Questo può rappresentare un problema in quanto il client spesso usa i business object oltre che per svolgere operazioni sul sistema soprattutto come contenitori di dati da visualizzare ed eventualmente da modificare. Avere accesso ai dati dei business object mediante getter e setter che in realtà si traducono in chiamate remote è chiaramente una tecnica inefficiente. L’altro problema riguarda la persistenza dei business object. Attualmente le specifiche degli EJB prevedono la persistenza degli Entity Bean gestita automaticamente dal container solo su database relazionali (peraltro senza specificare il tipo di mapping object/relational che deve essere supportato, ma lasciando massima libertà all’implementazione del container su tale argomento).  Questo non è sufficiente per quei progetti di integrazione di applicazioni legacy in cui gli EJB rappresentano dati salvati su un supporto diverso dal database relazionale. Oltre alla mancanza di supporto per altri tipi di persistenza ciò che manca è una netta separazione fra l’Entity Bean e la politica con cui deve essere gestita la sua persistenza. 
Alcuni di questi problemi vengono risolti dalle prossime specifiche EJB. In particolare per quanto riguarda il tema della persistenza su altri tipi di supporto è stata creata la tecnologia dei Connector. Un Connector può essere visto come un driver per un certo supporto di persistenza. In tal senso JDBC diverrebbe il Connector verso i database relazionali. Per quanto riguarda il problema di separare la politica di persistenza del Bean (quali parti dello stato del Bean devono essere resi persistenti) dal Bean stesso, con le nuove specifiche degli EJB si fa qualche passo avanti. Infatti è stato individuato il ruolo del Persistance Manager Provider, ovvero un ente che mette a disposizione del bean provider dei tools che permettano di definire in maniera dichiarativa quale sia la parte persistente (Abstract Schema) di un Entity Bean. Attualmente però il Persistance Manager gestisce la persistenza solo su database relazionali. Il problema, a mio avviso, è solo di natura tecnologica, questo implica che man mano che le specifiche EJB si faranno più raffinate è possibile che venga risolto naturalmente. Quello che intendo dire è che avendo introdotto uno strato di software (Persistance Manager) che enuclea la politica di persistenza di un Entity Bean e una tecnologia (i Connector) che consente di avere persistenza su qualunque supporto mediante una interfaccia uniforme, è possibile pensare che unendo le due cose presto potremo avere Entity Bean a cui si potrà cambiare il supporto di persistenza senza cambiarne il codice.
 

Aggregate Entities

Nome: Aggregate Entities.

Problema: il mapping isomorfo fra tabelle di un database relazionale e Entity Bean porta ad una proliferazione di Entity Bean che genera inefficienza nell’architettura EJB.

Relazioni con altre tecniche: Assieme a Value Object consente di scrivere applicazioni particolarmente efficienti.

Descrizione: Un problema che si presenta ogni volta che si decide di avere la persistenza dei propri dati su un database relazionale e di sviluppare l’applicazione con un linguaggio object oriented è quello del mapping degli oggetti dell’applicazione sulle tabelle del database. La maniera più naturale per risolvere il problema è quella di avere una classe per ogni tabella del database e un oggetto per ogni riga di tali tabelle. Questo approccio in realtà ha delle debolezze, infatti se il database è in una delle forme normali tenderà ad avere un numero elevato di tabelle alle quali dovrebbero corrispondere un numero elevato di classi. Una tale proliferazione di classi porta alcuni svantaggi, fra i quali la difficoltà di gestione del codice e la vulnerabilità del programma a variazioni dello schema del database in caso tali classi siano pubbliche.
Nel mondo EJB l’approccio di avere una classe per ogni tabella del database (anche detto isomorfismo object/relational ) si tradurrebbe nell’avere un Entity Bean per ogni tabella del database. Questo non è accettabile perché sovraccaricherebbe il container con la gestione di una quantità elevata di piccoli bean e causerebbe un grande numero di accessi al database. Per evitare tutto ciò l’Entity Bean deve contenere molti dati anche denormalizzati (ovvero deve essere di granularità più grossa rispetto a quella delle tabelle del database).
Dato un database in forma normale non è sempre facile scegliere la granularità che dovranno avere gli Entity Bean che lavorano su di esso. Un modo può essere quello di individuare gerarchie di entità forti e entità deboli. Nella notazione ER le entità deboli sono strettamente legate ad una entità forte e non possono esistere senza di essa. In genere questo tipo di relazione è modellata con una foreign key che parte dalla entità debole verso quella forte e che fa parte della primary key della entita debole.

Con questa tecnica difficilmente si può usare la Container Managed Persistance (CMP), infatti un Aggregate Entity Bean si mappa sul database relazionale in maniera piuttosto complessa tale da non rientrare nelle possibilità della CMP disponibile sulla maggior parte dei container.

Nelle specifiche EJB 2.0 è previsto esplicitamente che un Entity Bean possa avere riferimenti ad oggetti esterni detti Dependant Object. I Dependant Object sono oggetti java di cui è stata definita la persistenza mediante il Peristant Manager. I Dependant Object non sono Entity Bean, ma partecipano al ciclo di vita dell’Entity Bean da cui dipendono; quindi quando un Entity Bean viene reso persistente anche tutti i suoi Dependant Object vengono salvati. I Dependant Object sono dunque il candidato ideale a rappresentare le entità deboli del database.

Qui finisce la prima parte della raccolta di tecniche di programmazione degli EJB. Vi aspetto il mese prossimo per la seconda.
Gli esempi descritti in questo articolo possono essere scaricati qui
 
 

Bibliografia
[1] Sun Microsystem, “Enterprise Java Bean 2.0 Specification”, 2000
[2] Sun Microsystem, “Designing Enterprise Application with Java 2 Platform Enterprise Edition”, 2000
[3] Nova Laboratories, “The Developers’s Guide to Understanding Enterprise JavaBeans Applications”, 2000
[4] Addison Wesley, “Design Patterns: Elements of Reusable Object-Oriented Software” Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, and Grady Booch
 

Raffaele Spazzoli è laureato in ingegneria informatica. Da anni coltiva la propria passione per Java studiando le soluzioni tecnologiche introdotte dalla Sun.

Vai alla Home Page di MokaByte
Vai alla prima pagina di questo mese


MokaByte®  è un marchio registrato da MokaByte s.r.l.
Java® è un marchio registrato da Sun Microsystems; tutti i diritti riservati
E' vietata la riproduzione anche parziale
Per comunicazioni inviare una mail a
mokainfo@mokabyte.it