|
|||||||||||||||||||||||||||||||||
|
Lo sviluppo di applicazione distribuite ha visto negli ultimi tempi il passaggio dalle architetture client/server ai sistemi three-tier con client Web. Per quanto riguarda lo sviluppo del middle tier, quello che incorpora la logica applicativa, ci si basa sempre di più su componenti riusabili ai quali richiedere servizi esposti come metodi di un oggetto. |
|||||||||||||||||||||||||||||||||
| Introduzione
I più noti modelli di programmazione a oggetti distribuiti sono
Enterprise Java
Beans
EJB
Server
Container
Per ottimizzare le prestazioni un EJB container gestisce un pool di risorse in cui 'riporre' i bean non utilizzati. Il riferimento remoto rimane comunque attivo e a una seguente invocazione del client il container provvede a recuperare il bean dal pool. L'interazione fra un EJB e il suo container può avvenire attraverso metodi callback, l'oggetto EJBContext o JNDI.
Un componente EJB è costituito da diversi file:
import javax.ejb.EJBObject;
import javax.rmi.RMIException;
public interface Book extends EJBObject {
public String getCode() throws RemoteException;
public String getAuthor() throws RemoteException;
public void setAuthor(String author)
throws RemoteException;
public String getTitle() throws RemoteException;
public void setTitle(String title)
throws RemoteException;
}
L'interfaccia
Book
definisce metodi per accedere e modificare i dati che rappresentano un
libro e che saranno memorizzati su un'apposita tabella su database. Come
vedremo in seguito questi sono i tipici metodi di un particolare tipo di
EJB, gli entity bean, che rappresenta un oggetto memorizzato su
database.
Osserviamo come il codice precedente non definisca metodi applicativi; questi vengono infatti implementati da un diverso tipo di EJB, i session bean, e saranno definiti in una remote interface distinta. Supponiamo ad esempio di voler implementare la gestione di ordini di libri on-line: questa attività sarà realizzata attraverso un session bean che chiameremo OrderAgent e che avrà la seguente remote interface import javax.ejb.EJBObject;
import javax.rmi.RMIException;
public interface OrderAgent extends EJBObject {
public void placeOrder(Book book, Customer customer)
throws RemoteException;
}
Il metodo
placeOrder()
esegue l'inserimento di un ordine per un libro da parte di un cliente (le
cui informazioni sono rappresentate dal componente Customer) coinvolgendo
tutti gli entity bean necessari.
import javax.ejb.*;
import java.util.Collection;
import java.rmi.RemoteException;
public interface BookHome extends EJBHome {
public Book create(String code)
throws CreateException, RemoteException;
public Book findByPrimaryKey(String code)
throws FinderException, RemoteException;
public Collection findByAuthor(String author)
throws FinderException, RemoteException;
}
I metodi
findBy
della home interface permettono di recuperare un EJB o un'intera collezione
in base a vari criteri di selezione: findByPrimaryKey() restituisce
l'EJB corrispondente alla chiave primaria specificata mentre
findByAuthor()
restituisce una collezione di EJB di libri scritti dall'autore specificato.
Se non è possibile trovare i bean richiesti viene sollevata una
FinderException.
Gli entity bean implementano l'interfaccia EntityBean e modellano i dati presenti su database. Lo sviluppatore non deve quindi scrivere codice SQL per accedere o modificare i dati ma userà i metodi della remote interface. Vediamo come implementare il bean per il componente Book import javax.ejb.*;
public class BookEJB implements EntityBean {
private String code;
private String author;
private String title;
private EntityContext context;
// business methods
public String getCode() throws RemoteException {
return code;
}
public String getAuthor() throws RemoteException {
return author;
}
public void setAuthor(String author)
throws RemoteException {
this.author = author;
}
public String getTitle() throws RemoteException {
return title;
}
public void setTitle(String title)
throws RemoteException {
this.title = title;
}
// EntityContext handling
public void setEntityContext(EntityContext context) {
this.context = context;
}
public void unsetEntityContext() {
this.context = null;
}
// callback methods
public Integer ejbCreate(String code) {
// using container managed persistence
this.code = code;
return null;
}
public void ejbPostCreate(String code) {}
public void ejbLoad() {}
public void ejbStore() {}
public void ejbActivate() {}
public void ejbPassivate() {}
public void ejbRemove() {}
}
Il codice
precedente presenta i metodi applicativi definiti in precedenza nella remote
interface. Osserviamo però che la classe non implementa l'interfaccia
Book
perchè l'accesso a tali metodi è infatti mediato dal container.
I metodi setEntityContext() e unsetEntityContext() permettono
di impostare l'oggetto EntityContext che, come visto in precedenza,
rappresenta un riferimento al container. Seguono infine alcuni metodi callback
invocati dal container al verificarsi di determinati eventi durante il
ciclo di vita del bean.
Le gestione della persistenza per gli entity bean può essere di due tipi:
import javax.ejb.SessionBean;
public class OrderAgentEJB implements SessionBean {
public void placeOrder(Book book, Customer customer)
throws RemoteException {
Order order;
OrderHome orderHome;
orderHome = ... // home reference
order = orderHome.create(book.getCode(),
customer.getId());
}
}
Il codice
precedente, anche se molto semplificato, mostra comunque la possibilità
di poter distinguere componenti basati sui dati e componenti basati su
task.
Una delle maggiori novità introdotte con la nuova versione 2.0 delle specifiche EJB riguarda l'introduzione di un nuovo tipo di bean, i message driven bean, che si occupano di gestire i messaggi JMS. JMS è una API vendor-neutral per la gestione di sistemi di messaging asincrono. Si veda [3] per una introduzione a JMS. Prima della versione 2.0 degli EJB questi potevano accedere a servizi JMS attraverso JNDI; ora è possibile sviluppare client JMS che vengono eseguiti in un ambiente robusto e affidabile quale un container EJB. Vediamo uno scheletro di codice di un message driven bean. import javax.ejb.*;
import javax.jms.*;
public class MessageHandlerEJB implements MessageDrivenBean {
public void onMessage(Message message) {
// handle message
// ...
}
}
Quando
si esegue il deploy di un message driven bean si assegna ad esso quali
tipi di messaggio devono essergli instradati. E' inoltre importante osservare
che i messaggi non devono essere necessariamente generati da un altro EJB
ma anche ad esempio da un'applicazione legacy che pubblica un messaggio
in un prodotto compatibile con JMS.
Osserviamo
che per garantire la massima integrazione fra applicazioni è possibile
accedere ad un EJB come oggetto CORBA.
EJB 2.0
Il persistence manager è in grado di generare il mapping di entity bean verso database relazionali in base alle informazioni contenute nel descrittore del bean, come in EJB 1.1, ma sono state introdotte diverse novità
import javax.ejb.*;
public abstract BookEJB implements EntityBean {
// instance fields
private EntityContext context;
// business methods
public abstract String getCode() throws RemoteException;
public abstract String getAuthor() throws RemoteException;
public abstract void setAuthor(String author)
throws RemoteException;
// ...
}
Possiamo
osservare come nessuno degli attributi persistenti venga elencato nella
classe: questi verranno specificati nel deployment descriptor e il persistence
manager genererà la classe concreta corrispondente;
Conclusioni
Riferimenti
|
|||||||||||||||||||||||||||||||||
![]() |
|||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||
![]() |
|
||||||||||||||||||||||||||||||||