Guida minimale EJB3 (Prima Parte)

From Servizi RSI
Jump to: navigation, search

Guida minimale all’uso della persistenza in EJB3 (parte 1)

Questa guida è stata prodotta da: Aurelio D’Amico il 9 Luglio 2007

Requisiti

Il primo requisito per l’utilizzo di EJB3 è quello di avere installata una versione java compatibile, cioè java 5 o superiore. EJB3 fa un uso estensivo delle annotazioni che sono state introdotte con la versione 5 di java. Il secondo requisito è quello di avere un application server compatibile con EJB3. In questa guida useremo JBoss 4.0.5 GA di cui esiste anche un plugin per Eclipse.

JBoss

La strada più breve per installare JBoss come server EJB3 è quella di lanciare JEMS installer 1.2.0.GA direttamente dalla pagina web (http://labs.jboss.com/jemsinstaller/downloads). Si tratta di accettare tutti i valori già impostati tranne la tipologia del server che dovrà essere impostata a “ejb3- clustered”. (Consiglio comunque di cambiare anche la cartella di installazione in una facilmente raggiungibile. Es. C:\jboss-4.0.5.GA).Qualsiasi sia la cartella di installazione dora in avanti ci riferiremo ad essa come ${jboss}. Il nome del server che useremo sarà “default”, ma il nome può essere uno qualsiasi. La cartella di deploy dove copiare l’EAR dell’applicazione e gli archivi di configurazione dei servizi sarà: ${jboss}/server/nome_server/deploy. (Es. C:\jboss-4.0.5.GA\server\default\deploy)

Eclipse plug-in

La strada più breve è quella di istallare la versione completa di JBOSS IDE 2.0.0 Beta2 senza passare attraverso l’upgrade di Eclipse (http://labs.jboss.com/jbosside/download/). Per windows il file da scaricare è: JBossIDE-2.0.0.Beta2-Bundle-win32.zip

Datasource

Come primo passo abbiamo la necessità di configurare in JBoss un datasource da utilizzare. Nella cartella ${jboss}\docs\examples\jca si trovano alcuni esempi di connessione ai database più comuni (es. oracle, postgres, mysql, ecc…). Il nome dell’archivio di configurazione deve essere del tipo nome-ds.xml dove nome può essere uno qualsiasi. L’archivio deve trovarsi nella cartella di deploy: ${jboss}/server/default/deploy. Notare che il suffisso “-ds.xml” è necessario affinché JBoss riconosca l’archivio come configurazione di un datasource.

Esempio: (C:\jboss-4.0.5.GA\server\default\deploy\siper-ds.xml)


<datasources>
  <local-tx-datasource>
    <jndi-name>siper/datasource</jndi-name>
    <connection-url>jdbc:postgresql://localhost:5432/siper</connection-url>
    <driver-class>org.postgresql.Driver</driver-class>
    <user-name>x</user-name>
    <password>y</password>
    <new-connection-sql>select 1</new-connection-sql>
    <check-valid-connection-sql>select 1</check-valid-connection-sql>
    <metadata>
      <type-mapping>PostgreSQL 8.2</type-mapping>
    </metadata>
  </local-tx-datasource>
</datasources>

Persistence Framework

Java EJB3 persistence framework è una collezione di specifiche per la persistenza degli oggetti in un database relazionale. Queste specifiche in JBoss sono implementate dal framework Hibernate. (Non è un caso che uno dei creatori di Hibernate abbia partecipato alla stesura delle specifiche di persistenza per EJB3). La buona notizia è che EJB3 nasconde completamente la complessità di configurazione di Hibernate rendendo estremamente facile la mappatura degli oggetti col database e totalmente assente ogni tipo di configurazione. La novità è nell’utilizzo delle annotazioni introdotte con Java 5. Per i sentimentali c’è ancora la possibilità di utilizzare xml per la configurazione e la mappatura ma la nuova scuola di pensiero preferisce utilizzare direttamente le classi java come archivi di configurazione (se c’è una modifica di configurazione da fare si fa nella classe java piuttosto che in un archivio xml prolisso ed illeggibile evitando in questo modo la ridondanza e prolificazione del codice). Inoltre EJB3 adotta il pattern "Convention over Configuration" provvedendo una “ragionevole configurazione” di default che garantisce la copertura delle esigenze più comuni. Sarà quindi necessario intervenire solo per i casi “non convenzionali”.

Persistenza

Lo scopo della persistenza in un ambiente orientato agli oggetti è quella di salvare lo stato degli oggetti. Il persistence framework di EJB3 permette di utilizzare allo scopo un database relazionale. Per rendere questo possibile è necessario “mappare” una classe java ad una tabella e gli attributi della classe alle colonne della tabella.

Tabella di esempio: RUOLI.

La tabella che useremo come esempio sarà molto semplice e consta di due sole colonne RUOLO_ID e NOME.

Classe di esempio: Ruolo.java

Finalmente entriamo in merito alla bellezza ed eleganza di EJB3. La classe “entità” che utilizzeremo per la gestione e la persistenza dei ruoli sarà un semplicissima classe java con due attributi ed i loro metodi di accesso (che l’IDE è in grado di generare per voi):


public class Ruolo implements Serializable {
  private Integer ruoloId;
  private String nome;
  public Integer getRuoloId() {return ruoloId;}
  public void setRuoloId(Integer ruoloId) {this.ruoloId = ruoloId;}
  public String getNome() {return nome;}
  public void setNome(String nome) {this.nome = nome;}
}

POJO

Una piccola deviazione per introdurre il concetto di “Plain Old Java Object”. Se avete lavorato in precedenza con gli Enterprise Java Beans sapete bene che la struttura di un EJB era tuttaltro che semplice. EJB3 introduce il concetto di POJO. Tutti i tipi di enterprise bean in EJB3 sono semplici classi java. Saranno le annotazioni che indicheranno al compilatore quale codice iniettare per rendere la classe un bean enterprise.

Entity Bean

Per rendere la nostra classe un “entity bean” sarà sufficiente aggiungere l’annotazione @Entity:

@Entity
public class Ruolo implements Serializable {...}

Per rendere la classe completamente funzionante è necessario aggiungere solo un ulteriore annotazione, @Id , che indica al framework quale è l’attributo “chiave” dell’entità.

public class Ruolo implements Serializable {...  
  
  @Id
  public Integer getRuoloId() {return ruoloId;}

...}

Notare che abbiamo annotato il metodo di accesso, getRuoloId e non l’attributo. Anche se è possibile annotare l’attributo, è opinione comune che sia più saggio e flessibile annotare il metodo di accesso piuttosto che l’attributo (il metodo di accesso per esempio può contenere regole di business o addirittura utilizzare un attributo completamente differente).

Ulteriori annotazioni utili: @Table e @Column

A questo punto, per la legge della “configurazione ragionevole”, la nostra classe ha tutti i requisiti per essere utilizzata come un’entity bean dal framework di persistenza. Nel nostro caso però abbiamo bisogno di introdurre due ulteriori annotazioni che servono a bilanciare i nomi usati nel database con i nomi usati nella classe. Se ricordate abbiamo chiamato la tabella RUOLI e la classe di modello Ruolo.java. Per default il framework cercherà di associare alla classe una tabella con lo stesso nome per cui dobbiamo correggere questo comportamento dichiarando esplicitamente il nome della tabella da utilizzare attraverso l’uso dell’annotazione @Table.

@Entity @Table(name=”RUOLI”)
public class Ruolo implements Serializable {...}

Inoltre per convenzione sui nomi abbiamo deciso di usare ruoloId come nome di attributo da associare alla colonna RUOLO_ID. Il framework cercherà di associare all’attributo la colonna RUOLOID. Questa discrepanza si corregge utilizzando l’attributo @Column.

@Id @Column(name="RUOLO_ID")
public Integer getRuoloId() {return ruoloId;}

La classe completa a questo punto è la seguente:

@Entity @Table(name=”RUOLI”)
public class Ruolo implements Serializable {
  private Integer ruoloId;
  private String nome;
  @Id @Column(name="RUOLO_ID")
  public Integer getRuoloId() {return ruoloId;}
  public void setRuoloId(Integer ruoloId) {this.ruoloId = ruoloId;}
  public String getNome() {return nome;}
  public void setNome(String nome) {this.nome = nome;}
}

Fin qui sono state introdotte quattro annotazioni EJB3: @Entity, @Table, @Id e @Column. Queste quattro annotazioni sono tutto quello di cui si ha bisogno nella maggioranza dei casi per la “mappatura” di un entity bean con una entità nel database. L’associazione di una classe ad una tabella utilizzando per esempio un file di configurazione xml avrebbe richiesto una notevole quantità di codice xml.

Entity Manager

Per essere in grado di gestire la nostra entità, abbiamo bisogno di utilizzare l’entity manager che EJB3 mette a disposizione allo scopo. La strada più breve è quella di implementare una classe astratta che faccia il lavoro di implementazione dell’entity manager e lo renda disponibile agli EJB che la estendono.

Esempio: (C:\siper\ejb\src\it\cnr\siper\ejb\AbstractManager.java)


public abstract class AbstractManager {
  @PersistenceContext(unitName="siper")
  protected EntityManager manager;
}

L’annotazione @PersistenceContext indica al compilatore di iniettare il codice necessario per l’utilizzo di un tipo EntityManager. All’EJB che estenderà questa classe sarà sufficiente eseguire una delle numerose operazioni di persistenza che il manager mette a disposizione (es. manager.persist(object)).

Contesto di Persistenza.

A questo punto è opportuno domandarsi cosa stia ad indicare la proprietà unitName="siper" indicata nell’annotazione @PersistenceContext. Le specifiche di EJB3 richiedono un archivio di configurazione denominato persistence.xml da tenere nella cartella META-INF del JAR che racchiuderà gli EJB. Questo archivio serve a stabilire uno o più contesti di persistenza denominati persistence-unit. In pratica è possibile usare differenti connessioni a differenti database od anche ad uno stesso con differenti regole di connessione. Ad ogni unità di persistenza (connessione) si assegna un nome con il quale ci si riferisce durante la creazione del contesto di persistenza che l’EntityManager andrà ad utilizzare. A sua volta l’unità di persistenza sarà associata ad un nome di datasource configurato nell’application server utilizzato (nel nostro caso nella cartella di deploy di JBoss).

Esempio: META-INF\persistence.xml


<persistence>
  <persistence-unit name="siper">
    <jta-data-source>java:/siper/datasource</jta-data-source>
    <properties>
      <property name="Hibernate.hbm2ddl.auto" value="none"/>
      <property name="Hibernate.dialect" 
                value="org.Hibernate.dialect.PostgreSQLDialect"/>
      <property name="Hibernate.jdbc.batch_size">0</property>
      <property name="Hibernate.jdbc.use_streams_for_binary">false</property>
      <property name="Hibernate.show_sql">false</property>
    </properties>
  </persistence-unit>
</persistence>

Fate caso al tag <properties>. Sotto questo tag possono essere elencate le proprietà native del framework che implementa la persistenza EJB3. Nel caso di JBoss potete vedere che la persistenza è implementata attraverso il framework Hibernate.

CRUD

Finalmente siamo pronti ad eseguire le operazioni CRUD di base:

Creazione

Ruolo ruolo = new Ruolo();
ruolo.setRuoloId(1);
ruolo.setNome("ruolo di test");
manager.persist(ruolo)

Lettura

Ruolo ruolo = manager.find(Ruolo.class, 1);

Aggiornamento

Ruolo ruolo = manager.find(Ruolo.class, 1);
ruolo.setNome("ruolo di test modificato")
manager.merge(ruolo);

Eliminazione

manager.delete(1);

Conclusioni

Considerando i pochi archivi xml che è necessario creare, una tantum, per la configurazione del datasource e del contesto di persistenza, l’approccio introdotto da EJB3 è quantomeno fenomenale nel suo minimalismo. Nella mia esperienza di utilizzo di JDBC, J2EE e Hibernate non ho incontrato niente di meno prolisso ed allo stesso tempo tanto efficace. Spinta essenzialmente dalla competizione di Spring+Hibernate e Ruby on Rail, SUN è stata in grado in poco tempo di immettere nel mercato un prodotto veramente competitivo tanto che alcuni giornali specializzati come il “Java Developer Journal” hanno titolato all’uscita di EJB3 “chi ha più bisogno di spring e Hibernate?”.

Parte 2

Nella seconda parte creeremo un ejb come servizio di persistenza per la classe Ruolo.java e descriveremo come implementare query particolari usando EJB3 QL e SQL nativo e di come utilizzare JDBC per i casi di assoluta necessità.

Risorse


Questa guida è stata prodotta da: Aurelio D’Amico il 9 Luglio 2007