MokaByte 69 - Dicembre 2002 
I Java Data Object
Uno standard per la persistenza degli oggetti java
di
Federico Pavoncelli
It seems to me that Java Data Objects are what Entity Beans should have been like. (Floyd Marinescu)
We were perfectly correct - the 18 month "lifetime" granted to Entity JavaBeans will expire in July 2002. (Ogilvie Partners)
I haven't seen any compelling reason so far to use JDO instead of EJB 2.0 CMP... (Rickard Oberg)
"So far, Java DataObjects is still just a draft proposal (al 5/10/2001). So perhaps it will never see the light of day. We can at least hope" (Roger Sessions).

Introduzione
Quelli appena visti questi sono soltanto alcuni dei commenti sui Java Data Object, da parte degli esperti del settore.
Ma come stanno realmente le cose ? E' possibile avere qualche elemento in più che ci aiuti a formulare un giudizio corretto sui JDO?
In quest'articolo discuteremo questa nuova tecnologia, come è stata pensata, cosa promette, i suoi punti di forza e di debolezza, il supporto dato dai venditori.
In seguito, nei prossimi articoli, approfondiremo l'argomento, occupandoci di integrazione JDO-J2EE, con il confronto tra le strategie più utilizzate per la persistenza dei business object (Entity Bean, JDO, SLQ e pattern DAO) e con l'aiuto di esempi che presentino situazioni "reali", come capita di affrontare nel lavoro quotidiano.
Che ne dite? Se il programma vi piace, possiamo iniziare ……

 

I Java Data Object
Una delle critiche portate dai detrattori dei JDO è il troppo tempo trascorso dalla loro introduzione, datata Giugno 1999, alla nascita della prima versione delle specifiche, arrivata solamente a Marzo di quest'anno.
Questa critica passa in secondo piano non appena pensiamo all'ambizioso ed importante obiettivo dei JDO: essere per i prodotti di persistenza quello che la J2EE è per gli application server, un indiscusso standard comune.
JDO infatti si propone come uno standard per la persistenza di oggetti java, utilizzabile su tutti gli ambienti java (da J2ME a J2EE), accettato dai produttori di un'area che tradizionalmente è molto restia ad uniformarsi ad uno standard comune, capace di gestire trasparentemente diverse fonti dati (DBMS,ODBMS, ecc.ecc).
Anche se destinate a crescere, già oggi le implementazioni disponibili sono abbastanza numerose (vedi tabella1 e 2), pur senza il supporto ufficiale dei produttori leader del settore e con poche implementazioni open-source complete.
Le posizioni dei produttori più noti, sono diverse, ed in generale non molto benevole, e vanno da un parziale supporto (Oracle-Toplink e Exolab-Castor), ad una feroce critica (Thought-Cocobase).
Sul loro supporto futuro immagino che molto dipenda dal successo a breve dei JDO, perché sulle critiche iniziali alla nascita di uno standard comune, da parte di chi fino a ieri controllava un mondo proprietario, immagino abbiate già lo vostra idea a riguardo.

 


Tabella 1 -
Implementazioni JDO commerciali

 


Tabella 2
- Implementazioni JDO Open Source

 


Confronto con gli Entity Bean
Fin dalla loro introduzione i JDO sono stati accompagnati dall'idea di essere una tecnologia sostitutiva degli entity bean, nonostante Sun abbia sempre negato questa eventualità.
Vediamo ora le caratteristiche di entrambe le tecnologie per capire se, ed in quali condizioni, risultino essere sostitutive o complementari.

Gli entity fanno parte delle specifiche J2EE e nascono come dei componenti distribuiti che possono sfruttare tutta una serie di servizi garantiti loro da un container EJB, quali persistenza, sicurezza, transazionalità e gestione del ciclo di vita delle istanze (object pooling).
Sono stati pensati per la modellazione delle entità, i cosiddetti business object, anche se risentono da subito di alcuni problemi (quasi tutti legati al concetto di persistenza), affrontati e parzialmente risolti con le specifiche 2.0, che potremmo riassumere con:

  • Obbligatorietà dell'accesso utilizzando un'interfaccia remota.
  • Persistenza poco efficiente, difficilmente ottimizzabile per i container, con poche funzionalità.
  • Mapping macchinoso, per le troppe informazioni presenti nei deployment descriptor.
  • Mancanza di trasparenza dello strato di persistenza.Uso limitato agli EJB contatiner.

I JDO invece non fanno parte della J2EE ma sono integrabili con essa, e rispetto agli entity bean, si occupano soltanto del concetto di persistenza, senza considerare altre problematiche, come ad esempio transazioni distribuite, accessi remoti, meccanismi di sicurezza.
I JDO cercano una gestione della persistenza migliore e diversa rispetto agli entity CMP, ed infatti rispondono, da subito, a molti dei problemi degli entity:

  • Oggetti locali.
  • Persistenza performante e ricca di funzionalità.
  • Sviluppo semplificato, contenuto informativo dei descrittori di persistenza (chiamati metadati) ridotto.
  • Trasparenza assoluta dello strato di persistenza.
  • Possibilità di utilizzo con tutte le piattaforme JAVA, dalla semplice JVM ai container J2EE (le specifiche parlano di ambienti managed e non).

Quanto è ampia allora la sovrapposizione delle due tecnologie?
Sicuramente nel campo della persistenza è totale, per quel che riguarda gli altri servizi dipende dalla nostra architettura. Dobbiamo infatti ricordare che, se escludiamo la persistenza, anche i session bean forniscono gli stessi servizi ulteriori, e che quindi le due tecnologie possono diventare complementari o sostitutive a seconda delle nostre scelte architetturali.
Facciamo un paio di esempi per questi due scenari.
Se la nostra architettura utilizza il pattern session facade, per l'accesso delle entità da parte del web-tier (o del-client tier), siamo nelle migliori condizioni per la sostituzione degli entity con i JDO.
Se invece vogliamo esporre direttamente le entità (gli esempi sono solo ipotesi!) e controllare le autorizzazioni sulle chiamate di ciascun metodo esposto, in questo caso possiamo pensare ad un entity bean che utilizzi la persistenza dei JDO.

Difficile confermare, come alle volte si legge, che le implementazioni JDO siano per natura più performanti dei motori di persistenza CMP degli Entity. La diversità delle due specifiche nella sezione SPI, cioè nei cosiddetti contratti che i produttori devono soddisfare nella realizzazione di una implementazione, è certo una base di partenza su cui i produttori possono costruire, ma da qui a dire che le implementazioni JDO siano sicuramente più performanti………

Quando si parla di trasparenza dello strato di persistenza dei JDO, l'obiettivo è quello di permettere al programmatore di concentrarsi sulla logica di business, senza dover manualmente aggiungere nessuna istruzione di persistenza nelle classi che modellano i business object.
Questo codice può essere aggiunto alla classe con differenti modalità, che troviamo nelle specifiche e che possiamo riassumere con: prima della compilazione, dopo la compilazione, direttamente nel codice (in questo caso senza la trasparenza cercata!!!).
Finora tutti i produttori utilizzano la seconda soluzione, con un tool chiamato enhancer, che modifica (anzi, sostituisce) la classe originaria con una capace di persistere.
L'enhancer, ed il codice aggiunto alla classe sono diversi per ciascuna implementazione, ma tutti compatibili, dato che un requisito fissato dalle specifiche è la compatibilità binaria tra le classi "enhanced" dalle diverse implementazioni JDO.
Non sono moltissime le differenze su quest'argomento tra gli entity CMP e i JDO: in entrambi i casi non è il programmatore applicativo che si occupa di scrivere il codice di persistenza, per gli entity di solito lo aggiunge il container a tempo di deploy, per i jdo le specifiche propongono un enhancer. L'unica è forse che gli entity CMP obbligano sempre il programmatore ad implementare anche un'interfaccia (chiamata EntityBean), che però nella modalità CMP ha spesso metodi vuoti o istruzioni di debugging.

Assieme alla fase di enhancing praticamente tutti i produttori affiancano un tool per generare la struttura della base dati su cui far persistere gli oggetti, un file con istruzioni SLQ-DDL specifico per il database da utilizzare.
Ma se la base dati, come spesso capita sui progetti, esiste già ? Le specifiche non affrontano l'argomento, lasciando ai venditori dei tag proprietari per descrivere il mapping E-R.
Ecco spiegato perché nei tutorial su JDO si preferisce ricostruire o modificare la base dati ad ogni modifica delle classi, invece di utilizzarne una già definita.
E' quindi realistico che, in questa situazione, i metadati aumentino di complessità, a causa di estensioni non standard, in parte tradendo la promessa di poche informazioni nei metadati.
Magari in futuro torneremo sull'argomento, ma, come si dice in questi casi, difficile avere "la botte piena e la moglie ubriaca.."
Prima di vedere un esempio in figura 1 c'e' uno schema delle operazioni che seguiremo nel processo di sviluppo:


Figura 1

(clicca per ingrandire)

 

Un primo esempio
Prendiamo una normale classe java e cerchiamo di farla persistere.
Cliente ha tre semplici attributi: nome, cognome, data di nascita.


Figura 2


Prepariamo il file dei metadati che indichi all'enhancer le classi persistenti.
Ecco Cliente.jdo

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE jdo SYSTEM " jdo.dtd">
<jdo>
<package name="it.fpavo.ordini.business.model">
<class name="Cliente" />
</package>
</jdo>

Notate che non abbiamo specificato field e colonne. Ci siamo messi nella situazione in cui è l'oggetto java che controlla la base dati, e non viceversa.

Compiliamo ora Cliente.java, eseguiamo l'enhancer con Cliente.jdo e Cliente.class, ed otteniamo il nuovo Client.class
Non abbiamo ancora la base dati e quindi eseguiamo il tool per generarla (nella implementazione JDO che uso, è chiamato Schema Generator).
Eccone il contenuto (per HSQLDB):

CREATE TABLE ifobm_Cliente (
LIDOID BIGINT NOT NULL ,
nome VARCHAR(255) NULL ,
cognome VARCHAR(255) NULL ,
dataNascita DATETIME NULL )

CREATE UNIQUE INDEX ifobm_Cliente_LIDOID ON ifobm_Cliente ( LIDOID )

CREATE TABLE LIDOIDTABLE (
LIDOID BIGINT NOT NULL ,
LIDOTYPE VARCHAR(255) NOT NULL )

CREATE UNIQUE INDEX index_LIDOID ON LIDOIDTABLE ( LIDOID )
CREATE INDEX index_LIDOTYPE ON LIDOIDTABLE ( LIDOTYPE )
CREATE TABLE LIDOIDMAX ( LIDOLAST BIGINT NOT NULL )
INSERT INTO LIDOIDMAX VALUES( 0 )

Per ora vogliamo provare il nostro esempio in un ambiente non managed, e quindi scriviamo una classe TestCliente che si occupi di inserire un Cliente e di visualizzare tutti i Clienti del sistema.

Ecco il codice significativo di TestCliente.java:

//import necessari
import ordini.business.model.Cliente;
import java.util.Date;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;
import javax.jdo.Extent;
import javax.jdo.JDOHelper;
import java.util.Properties;


Properties prop;

// creazione di un nuovo cliente
Cliente cliente = new Cliente("federico","pavo",new Date());

// l'oggetto prop contiene alcune informazioni obbligatorie
// per poter agganciare la PersistenceManagerFactory
// e di solito riflette il contenuto di un file esterno

PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(prop);

PersistenceManager pm = pmf.getPersistenceManager();

Transaction t = pm.currentTransaction();

// dopo aver ottenuto un PersistenceManager ed una Transaction
// possiamo iniziare

t.begin();
pm.makePersistent(cliente);
t.commit();

// il cliente è diventato persistente
// visualizziamo ora i clienti del sistema

t.begin();
Extent clienti = pm.getExtent(Cliente.class, false);

System.out.println("--------------------------------");
System.out.println("Lista clienti: ");
System.out.println("--------------------------------");

Iterator i = clienti.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}

System.out.println("--------------------------------");
System.out.println("Terminata");
System.out.println("--------------------------------");

// rilascio delle risorse
clienti.close(i);
t.commit();
pm.close();

A questo punto desidero aggiungere solo un paio di precisazioni ai commenti che trovate nel codice dell'esempio.
L'oggetto più importante è sicuramente il PersistenceManager, che si occupa di salvare e successivamente ricercare gli oggetti Cliente, rispettivamente con i metodi makePersistence() e getExtent(). Gli altri oggetti coinvolti, PersistenceManagerFactory e Transaction, sono, se vogliamo di contorno, ed infatti in un ambiente managed saranno gestiti diversamente, con JNDI e JTA.
L'ambiente che ho utilizzato per i test è composto da ant, hsqsldb, lido di Libelis, j2sdk1.4.
Non è complesso installare e provare il tutto, anche se ci sono alcuni dettagli che possono farvi perdere molto tempo, come ad esempio la necessaria presenza di alcuni file di configurazione e delle licenze nel classpath, eccezioni dell'enhancer con descrizione vuota, i class file non correttamente cancellati.
Per evitare questi problemi e per tanti altri motivi, nel prossimo articolo presenterò un ambiente che automatizzerà l'installazione e l'esecuzione dei test, e comunque, prima di allora, sono raggiungibile per e-mail.

 

Conclusioni
Penso sia difficile e complesso per tutti pronosticare il futuro di una tecnologia, per via dei tanti fattori che ne concorrono a determinare il successo o la prematura scomparsa.
Il nostro approccio con i JDO è stato quello di discuterla e, nei prossimi articoli, cercare di applicarla alla piattaforma J2EE in un'architettura simile a quelle dei progetti più evoluti e moderni.
Ma forse c'e' già un valido motivo per cui i JDO saranno la tecnologia del futuro……
Roger Sessions, CEO di ObjectWatch, società di consulenza su .NET e J2EE, il 4 Agosto 1999 su COM+ ed EJB affermava "COM+ is mature. …EJB is immature and unproven technology"
Lunga vita a JDO, quindi…….

 

Bibliografia
[1] La home dei JDO - http://java.sun.com/products/jdo/
[2] Il JSR12 dei JDO - http://jcp.org/en/jsr/detail?id=012
[3] Uno dei siti di riferimento - http://www.jdocentral.com

Risorse
Scarica qui i sorgenti presentati nell'articolo


Federico Pavoncelli si occupa di architetture software in ambito JAVA, come consulente e docente per le più importanti società di software. Può essere contattato all'indirizzo e-mail fpavoncelli@mokabyte.it

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it