6. Versione 2: Architettura OpenEJB / JPA
6.1. Introduzione ai principi di porting
Qui presentiamo i principi che regoleranno il porting di un'applicazione JPA / Spring / Hibernate in un'applicazione JPA / OpenEJB / EclipseLink. Attenderemo fino alla Sezione 6.2 per creare i progetti Maven.
6.1.1. Le due architetture
L'attuale implementazione con Spring / Hibernate
![]() |
L'implementazione da realizzare con OpenEJB / EclipseLink
![]() |
6.1.2. Librerie del progetto
- I livelli [DAO] e [business] non vengono più istanziati da Spring. Vengono istanziati dal contenitore OpenEJB.
- Le librerie del contenitore Spring e la relativa configurazione sono sostituite dalle librerie del contenitore OpenEJB e dalla relativa configurazione.
- Le librerie del livello JPA / Hibernate sono sostituite da quelle del livello JPA / EclipseLink
6.1.3. Configurazione del livello JPA / EclipseLink / OpenEJB
- Il file [META-INF/persistence.xml] che configura il livello JPA diventa il seguente:
- Riga 3: Le transazioni in un contenitore EJB sono di tipo JTA (Java Transaction API). Con Spring erano di tipo RESOURCE_LOCAL.
- Riga 9: L'implementazione JPA utilizzata è EclipseLink
- Righe 5–7: Entità gestite dal livello JPA
- righe 11–13: proprietà del provider EclipseLink
- riga 12: le tabelle verranno create ad ogni esecuzione
Le caratteristiche JDBC della fonte dati JTA utilizzata dal contenitore OpenEJB saranno specificate dal seguente file di configurazione [conf/openejb.conf]:
- Riga 3: utilizziamo l'ID "Default JDBC Database" quando lavoriamo con un contenitore OpenEJB incorporato all'interno dell'applicazione stessa.
- Riga 5: utilizziamo un database MySQL [dbpam_eclipselink]
6.1.4. Implementazione del livello [DAO] utilizzando gli EJB
- Le classi che implementano il livello [DAO] diventano EJB. Prendiamo l'esempio della classe [CotisationDao]:
L'interfaccia [ICotisationDao] nella versione Spring era la seguente:
L'EJB implementerà questa stessa interfaccia in due forme diverse: una locale e una remota. L'interfaccia locale può essere utilizzata da un client in esecuzione nella stessa JVM, mentre l'interfaccia remota può essere utilizzata da un client in esecuzione in una JVM diversa.
L'interfaccia locale:
- Riga 6: L'interfaccia [ICotisationDaoLocal] eredita dall'interfaccia [ICotisationDao] per adottare tutti i suoi metodi. Non ne aggiunge di nuovi.
- Riga 5: l'annotazione @Local la rende un'interfaccia locale per l'EJB che la implementerà.
L'interfaccia remota:
- Riga 6: L'interfaccia [ICotisationDaoRemote] eredita dall'interfaccia [ICotisationDao] per adottare tutti i suoi metodi. Non ne aggiunge di nuovi.
- Riga 5: L'annotazione @Remote la rende un'interfaccia remota per l'EJB che la implementerà.
Il livello [DAO] è implementato da un EJB che implementa entrambe le interfacce (questo non è obbligatorio):
- riga 1: l'annotazione @Stateless, che rende la classe un EJB
- riga 2: l'annotazione @TransactionAttribute, che garantisce che ogni metodo della classe venga eseguito all'interno di una transazione.
- riga 5: l'annotazione @PersistenceContext, che inietta l'EntityManager del livello JPA nella classe [CotisationDao]. È identica a quella che avevamo nella versione Spring.
Quando viene utilizzata l'interfaccia locale del livello [DAO], il client di questa interfaccia viene eseguito nella stessa JVM.
![]() |
In precedenza, i livelli [business] e [DAO] si scambiano oggetti per riferimento. Quando un livello modifica l'oggetto condiviso, l'altro livello rileva tale modifica.
Quando si utilizza l'interfaccia remota del livello [DAO], il client di tale interfaccia viene solitamente eseguito in un'altra JVM.
![]() |
Nel diagramma sopra, i livelli [business] e [DAO] scambiano oggetti per valore (serializzazione dell'oggetto scambiato). Quando un livello modifica un oggetto condiviso, l'altro livello vede questa modifica solo se l'oggetto modificato gli viene restituito.
6.1.5. Implementazione del livello [business] utilizzando un EJB
- La classe che implementa il livello [business] diventa anche un EJB che implementa un'interfaccia locale e una remota. L'interfaccia [IMetier] iniziale era la seguente:
Creiamo un'interfaccia locale e un'interfaccia remota basate sull'interfaccia precedente:
L'EJB nel livello [business] implementa queste due interfacce:
- Righe 1-2: definiscono un EJB in cui ogni metodo viene eseguito all'interno di una transazione.
- riga 7: un riferimento all'interfaccia locale dell'EJB [CotisationDao].
- riga 6: l'annotazione @EJB indica al contenitore EJB di iniettare un riferimento all'interfaccia locale dell'EJB [CotisationDao].
- Righe 8–11: procediamo allo stesso modo per le interfacce locali degli EJB [EmployeeDao] e [CompensationDao].
In definitiva, quando l'EJB [Metier] viene istanziato, i campi nelle righe 7, 9 e 11 verranno inizializzati con riferimenti alle interfacce locali dei tre EJB nel livello [DAO]. Stiamo quindi supponendo qui che i livelli [business] e [DAO] verranno eseguiti nella stessa JVM.
![]() |
6.1.6. Client EJB
![]() |
Nel diagramma sopra riportato, per comunicare con il livello [business], il livello [ui] deve ottenere un riferimento all'interfaccia remota dell'EJB nel livello [business].
![]() |
Nel diagramma sopra riportato, per comunicare con il livello [business], il livello [UI] deve ottenere un riferimento all'interfaccia locale dell'EJB del livello [business]. Il metodo per ottenere questi riferimenti varia da un contenitore all'altro. Per il contenitore OpenEJB, è possibile procedere come segue:
Riferimento all'interfaccia locale:
- Righe 2–5: Il contenitore OpenEJB viene inizializzato.
- Riga 5: Abbiamo un contesto JNDI (Java Naming and Directory Interface) che ci permette di ottenere riferimenti agli EJB. Ogni EJB è identificato da un nome JNDI:
- (continua)
- per l'interfaccia locale, aggiungere "Local" al nome dell'EJB (righe 7-9)
- Per l'interfaccia remota, aggiungiamo "Remote" al nome dell'EJB
Con Java EE 5, queste regole variano a seconda del contenitore EJB. Questa è una sfida. Java EE 6 ha introdotto una notazione JNDI che è portabile su tutti i server applicativi.
Il codice precedente recupera i riferimenti alle interfacce locali degli EJB tramite i loro nomi JNDI. Abbiamo già accennato al fatto che questi potrebbero essere ottenuti anche tramite l'annotazione @EJB. Potremmo quindi scrivere:
L'annotazione @EJB viene presa in considerazione solo se appartiene a una classe caricata dal contenitore EJB. Questo sarà il caso, ad esempio, della classe [Metier]. Il codice sopra riportato, tuttavia, appartiene a una classe console che non verrà caricata dal contenitore EJB. Siamo quindi costretti a utilizzare i nomi JNDI degli EJB.
Di seguito è riportato il codice per ottenere un riferimento all'interfaccia remota dell'EJB [Metier]:
6.2. Esercizio pratico
Proponiamo di migrare l'applicazione NetBeans Spring/Hibernate verso un'architettura OpenEJB/EclipseLink.
L'attuale implementazione con Spring / Hibernate
![]() |
L'implementazione da realizzare con OpenEJB / EclipseLink
![]() |
6.2.1. Configurazione del database [ dbpam_eclipselink]
Se non esiste, creare il database MySQL [dbpam_eclipselink]. Se esiste, eliminare tutte le sue tabelle. Creare una connessione NetBeans a questo database come descritto nella sezione 6.2.1.
6.2.2. Configurazione iniziale del progetto NetBeans
- Caricare il progetto Maven [mv-pam-spring-hibernate]
- Creare un nuovo progetto Java Maven [mv-pam-openejb-eclipselink] [1]
![]() |
- Nella scheda [Files] [2], creare una cartella [conf] [3] nella directory principale del progetto
- Inserisci il seguente file [openejb.conf] [4] in questa cartella:
![]() |
- Crea la cartella [src/main/resources/META-INF] [5]
- Inserisci al suo interno il seguente file [persistence.xml] [6]:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="dbpam_eclipselinkPU" transaction-type="JTA">
<!-- the supplier JPA is EclipseLink -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- jpa entities -->
<class>jpa.Cotisation</class>
<class>jpa.Employe</class>
<class>jpa.Indemnite</class>
<!-- properties provider EclipseLink -->
<properties>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>
- Riga 12: richiediamo log dettagliati da EclipseLink,
- riga 13: le tabelle verranno create all'istanziazione del livello JPA,
- Aggiungi le librerie OpenEJB ed EclipseLink, oltre al driver JDBC di MySQL, al file [pom.xml] del progetto:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>istia.st</groupId>
<artifactId>mv-pam-openejb-eclipselink</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>mv-pam-openejb-eclipselink</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>openejb-core</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.swinglabs</groupId>
<artifactId>swing-layout</artifactId>
<version>1.0.3</version>
</dependency>
</dependencies>
<repositories>
<repository>
<url>http://download.eclipse.org/rt/eclipselink/maven.repo/</url>
<id>eclipselink</id>
<layout>default</layout>
<name>Repository for library Library[eclipselink]</name>
</repository>
</repositories>
</project>
- righe 18–22: la dipendenza OpenEJB,
- righe 30–39: le dipendenze EclipseLink,
- righe 41-44: la dipendenza del driver JDBC di MySQL
6.2.3. Porting del livello [DAO]
Eseguiremo il porting del livello [DAO] copiando i pacchetti dal progetto [mv-pam-spring-hibernate] al progetto [mv-pam-openejb-eclipselink].
- Copiare i pacchetti [dao, exception, jpa]
![]() |
Gli errori segnalati sopra sono dovuti al fatto che il livello [DAO] copiato utilizza Spring e le librerie Spring non fanno più parte del progetto.
6.2.3.1. L'EJB [CotisationDao]
Creiamo le interfacce locali e remote per il futuro EJB [CotisationDao]:
L'interfaccia locale ICotisationDaoLocal:
Per garantire il corretto import dei pacchetti, clicca con il tasto destro del mouse sul codice e seleziona [Correggi importazioni].
L'interfaccia remota ICotisationDaoRemote:
Quindi modifichiamo la classe [CotisationDao] per trasformarla in un EJB:
L'importazione che questa classe effettuava sul framework Spring scompare. Eseguire un [Clean and Build] sul progetto:
![]() |
In [1], non ci sono più errori nella classe [CotisationDao].
6.2.3.2. Gli EJB [EmployeDao] e [IndemniteDao]
Ripetiamo lo stesso processo per gli altri elementi del livello [DAO]:
- interfacce IEmployeDaoLocal e IEmployeDaoRemote derivate da IEmployeDao
- EJB `EmployeDao` che implementa queste due interfacce
- interfacce IIndemniteDaoLocal e IIndemniteDaoRemote derivate da IIndemniteDao
- EJB IndemniteDao che implementa queste due interfacce
Una volta fatto questo, non ci sono più errori nel progetto [2].
6.2.3.3. La classe [PamException]
La classe [PamException] rimane la stessa di prima, con una piccola modifica:
È stata aggiunta la riga 5. Per ottenere le importazioni corrette, fare clic su [Correggi importazioni].
Per comprendere l'annotazione alla riga 5, ricorda che ogni metodo negli EJB del nostro livello [DAO]:
- viene eseguito all'interno di una transazione avviata e terminata dal contenitore EJB
- genera una [PamException] non appena si verifica un errore
![]() |
Quando il livello [business] chiama un metodo M del livello [DAO], questa chiamata viene intercettata dal contenitore EJB. È come se ci fosse una classe intermedia tra il livello [business] e il livello [DAO] — qui chiamata [EJB Proxy] — che intercetta tutte le chiamate al livello [DAO]. Quando la chiamata al metodo M del livello [DAO] viene intercettata, l'EJB Proxy avvia una transazione e poi passa il controllo al metodo M del livello [DAO], che viene quindi eseguito all'interno di quella transazione. Il metodo M può completarsi con o senza un'eccezione.
- Se il metodo M termina senza un'eccezione, il controllo ritorna all'EJB proxy, che termina la transazione eseguendone il commit. Il controllo viene quindi restituito al metodo chiamante nel livello [business]
- Se il metodo M termina con un'eccezione, l'esecuzione ritorna al proxy EJB, che termina la transazione eseguendone il rollback. Inoltre, avvolge questa eccezione in un'EJBException. L'esecuzione torna quindi al metodo chiamante nel livello [business], che riceve quindi un'EJBException. L'annotazione alla riga 5 sopra impedisce questo incapsulamento. Il livello [business] riceverà quindi una PamException. Inoltre, l'attributo rollback=true indica al proxy EJB che, quando riceve una PamException, deve eseguire il rollback della transazione.
6.2.3.4. Test del livello [DAO]
Il nostro livello [DAO] implementato da EJB può essere testato. Iniziamo copiando il pacchetto [dao] da [Test Packages] nel progetto [mv-pam-springhibernate] nel progetto attualmente in fase di sviluppo [1]:
![]() |
Manteniamo solo il test [JUnitInitDB], che inizializza il database con alcuni dati [2]. Rinominiamo la classe [JUnitInitDbLocal] [3]. La classe [JUnitInitDBLocal] utilizzerà l'interfaccia locale degli EJB del livello [DAO].
Per prima cosa, modifichiamo la classe [JUnitInitDBLocal] come segue:
- righe 3-5: riferimenti alle interfacce locali degli EJB nel livello [DAO]
- riga 7: @BeforeClass annota il metodo eseguito all'avvio del test JUnit
- righe 10-13: inizializzazione del contenitore OpenEJB. Questa inizializzazione è proprietaria e varia a seconda del contenitore EJB.
- riga 13: disponiamo di un contesto JNDI (Java Naming and Directory Interface) che consente l'accesso agli EJB tramite nomi. Con OpenEJB, l'interfaccia locale di un EJB è indicata da ELocal e l'interfaccia remota da ERemote.
- Righe 15–17: richiediamo un riferimento alle interfacce locali degli EJB [EmployeDao, CotisationDao, IndemniteDao] dal contesto JNDI.
![]() |
Compilare il progetto, avviare il server MySQL se necessario ed eseguire il test JUnitInitDBLocal. Si noti che il file [persistence.xml] è stato configurato per ricreare le tabelle ad ogni esecuzione. Prima di eseguire il test, è consigliabile eliminare tutte le tabelle presenti nel database MySQL [dbpam_eclipselink].
![]() |
- In [1], nella scheda [Servizi], eliminare le tabelle dalla connessione NetBeans stabilita nella sezione 6.2.1.
- In [2], il database [dbpam_eclipselink] non contiene più alcuna tabella
- In [3], il progetto viene compilato
- In [4], viene eseguito il test JUnitInitDBLocal
![]() |
- In [5], il test è stato superato
- In [6], si aggiorna la connessione NetBeans
- in [7], vediamo le 4 tabelle create dal livello JPA. Lo scopo del test era di popolarle. Visualizziamo il contenuto di una di esse
![]() |
- in [8], il contenuto della tabella [EMPLOYEES]
Il container OpenEJB ha visualizzato i log nella console:
- righe 2-3: i due nomi JNDI dell'EJB [CotisationDaoLocal],
- righe 4-5: i due nomi JNDI dell'EJB [CotisationDaoRemote],
- righe 7-8: i due nomi JNDI dell'EJB [EmployeDaoLocal],
- righe 9-10: i due nomi JNDI dell'EJB [EmployeDaoRemote],
- righe 12-13: i due nomi JNDI dell'EJB [IndemniteDaoLocal],
- righe 14–15: i due nomi JNDI dell'EJB [EmployeeDaoRemote].
Eseguiamo nuovamente lo stesso test, questa volta utilizzando l'interfaccia remota degli EJB.
![]() |
In [1], la classe [JUnitInitDBLocal] è stata duplicata (copia/incolla) in [JUnitInitDBRemote]. In questa classe, sostituiamo le interfacce locali con quelle remote:
Una volta fatto ciò, è possibile eseguire la nuova classe di test. Prima di farlo, utilizzando la connessione NetBeans [dbpam_eclipselink], eliminare le tabelle dal database [dbpam_eclipselink].
![]() |
Con la connessione NetBeans [dbpam_eclipselink], verificare che il database sia stato popolato.
6.2.4. Porting del livello [business]
Eseguiremo il porting del livello [business] copiando i pacchetti dal progetto [mv-pam-spring-hibernate] al progetto [mv-pam-openejb-eclipselink].
![]() |
Gli errori segnalati sopra [1] sono dovuti al fatto che il livello [business] copiato utilizza Spring e le librerie Spring non fanno più parte del progetto.
6.2.4.1. L'EJB [Business]
Seguiamo la stessa procedura descritta per l'EJB [CotisationDao]. Innanzitutto, in [2], creiamo le interfacce locali e remote per il futuro EJB [Metier]. Entrambe derivano dall'interfaccia iniziale [IMetier].
Una volta fatto ciò, in [3] modifichiamo la classe [Business] in modo che diventi un EJB:
- riga 1: l'annotazione @Stateless rende la classe un EJB
- riga 2: ogni metodo della classe verrà eseguito all'interno di una transazione
- riga 3: l'EJB [Metier] implementa sia l'interfaccia locale che quella remota che abbiamo appena definito
- riga 7: l'EJB [Metier] utilizzerà l'EJB [CotisationDao] tramite la sua interfaccia locale. Ciò significa che i livelli [business] e [DAO] devono essere eseguiti nella stessa JVM.
- Riga 6: l'annotazione @EJB garantisce che il contenitore EJB inietti il riferimento all'interfaccia locale dell'EJB [CotisationDao] stesso. L'altro approccio che abbiamo incontrato consiste nell'utilizzare un contesto JNDI.
- Righe 8–11: Lo stesso meccanismo viene utilizzato per gli altri due EJB nel livello [DAO].
6.2.4.2. Test del livello [business]
Il nostro livello [business], implementato da un EJB, può essere testato. Iniziamo copiando il pacchetto [business] da [Test Packages] nel progetto [mv-pam-spring-hibernate] nel progetto attualmente in fase di sviluppo [1]:
![]() |
- in [1], il risultato della copia
- in [2], eliminiamo il primo test
- in [3], il test rimanente viene rinominato [JUnitMetierLocal]
La classe [JUnitMetierLocal] diventa la seguente:
- riga 4: un riferimento all'interfaccia locale dell'EJB [Metier]
- righe 8-12: configurazione del contenitore OpenEJB identica a quella utilizzata nel test del livello [DAO]
- righe 15–19: richiediamo riferimenti dal contesto JNDI alla riga 12 ai tre EJB nel livello [DAO] e all'EJB nel livello [business]. Gli EJB nel livello [DAO] saranno utilizzati per inizializzare il database, mentre l'EJB nel livello [business] sarà utilizzato per eseguire i test di calcolo dello stipendio.
L'esecuzione del test [JUnitMetierLocal] produce il seguente risultato [1]:
![]() |
In [2], duplichiamo [JUnitMetierLocal] come [JUnitMetierRemote] per testare questa volta l'interfaccia remota dell'EJB [Metier]. Il codice di [JUnitMetierRemote] viene modificato per utilizzare questa interfaccia remota. Il resto rimane invariato.
- righe 4 e 19: utilizziamo l'interfaccia remota dell'EJB [Business].
- righe 15–17: utilizziamo le interfacce remote del livello [DAO]
- righe 34–35: poiché con le interfacce remote gli oggetti scambiati tra il client e il server vengono passati per valore, dobbiamo recuperare il risultato restituito dal metodo create(Indemnite i). Ciò non era necessario con le interfacce locali, dove gli oggetti vengono passati per riferimento.
Una volta fatto ciò, è possibile compilare il progetto ed eseguire il test [JUnitMetierRemote]:
![]() |
6.2.5. Porting del livello [console]
Eseguiremo il porting del livello [console] copiando i pacchetti dal progetto [mv-pam-spring-hibernate] al progetto [mv-pam-openejb-eclipselink].
![]() |
Gli errori segnalati sopra [1] derivano dal fatto che il livello [business] copiato utilizza Spring, mentre le librerie Spring non fanno più parte del progetto. In [2], la classe [Main] viene rinominata [MainLocal]. Utilizzerà l'interfaccia locale dell'EJB [Business].
Il codice della classe [MainLocal] cambia come segue:
Le modifiche si trovano alle righe 13–25. In questo modo otteniamo un riferimento al livello [business], che è stato modificato (righe 17–22). Non spiegheremo il nuovo codice, poiché è già stato trattato negli esempi precedenti. Una volta apportate queste modifiche, il progetto non presenta più alcun errore (vedi [3]).
Configuriamo il progetto per l'esecuzione con argomenti [1]:
![]() |
Affinché l'applicazione console funzioni correttamente, è necessario che il database contenga dei dati. A tal fine, è necessario modificare il file [META-INF/persistence.xml]:
La riga 14, che causava la ricreazione delle tabelle del database ad ogni esecuzione, è stata commentata. È necessario ricompilare il progetto (Clean e Build) affinché questa modifica abbia effetto. Una volta fatto ciò, è possibile eseguire il programma. Se tutto va bene, l'output della console sarà simile al seguente:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="dbpam_eclipselinkPU" transaction-type="JTA">
<!-- the supplier JPA is EclipseLink -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- jpa entities -->
<class>jpa.Cotisation</class>
<class>jpa.Employe</class>
<class>jpa.Indemnite</class>
<!-- properties provider EclipseLink -->
<properties>
<property name="eclipselink.logging.level" value="FINE"/>
<!--
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
-->
</properties>
</persistence-unit>
</persistence>
Qui abbiamo utilizzato l'interfaccia locale del livello [business]. Ora utilizziamo la sua interfaccia remota in una seconda classe console:
![]() |
In [1], la classe [MainLocal] è stata duplicata in [MainRemote]. Il codice in [MainRemote] è stato modificato per utilizzare l'interfaccia remota del livello [business]:
Sono state apportate modifiche alle righe 2 e 8. Il progetto è configurato [2] per eseguire la classe [MainRemote]. L'esecuzione produce gli stessi risultati di prima.
6.3. Conclusione
Abbiamo dimostrato come migrare un'architettura Spring/Hibernate a un'architettura OpenEJB/EclipseLink.
L'architettura Spring/Hibernate
![]() |
L'architettura OpenEJB/EclipseLink
![]() |
Il processo di porting è andato liscio perché l'applicazione originale era stata strutturata a livelli. È importante comprendere questo punto.




























