6. نسخهٔ ۲: معماری OpenEJB / JPA
6.1. مقدمهای بر اصول مهاجرت
در اینجا اصولی را که بر انتقال یک برنامه JPA / Spring / Hibernate به یک برنامه JPA / OpenEJB / EclipseLink حاکم است، تشریح میکنیم. برای ایجاد پروژههای Maven تا بخش 6.2 صبر خواهیم کرد.
6.1.1. دو معماری
پیادهسازی فعلی با Spring / Hibernate
![]() |
پیادهسازی که باید با استفاده از OpenEJB / EclipseLink ساخته شود
![]() |
6.1.2. کتابخانههای پروژه
- لایههای [DAO] و [metier] دیگر توسط Spring نمونه سازی نمیشوند. آنها توسط کانتینر OpenEJB نمونه سازی میشوند.
- کتابخانهها و پیکربندی کانtejner Spring با کتابخانهها و پیکربندی کانtejner OpenEJB جایگزین میشوند.
- کتابخانههای لایه JPA / Hibernate با کتابخانههای لایه JPA / EclipseLink جایگزین میشوند
6.1.3. پیکربندی لایه JPA / EclipseLink / OpenEJB
- فایل [META-INF/persistence.xml] که لایه JPA را پیکربندی میکند، به شرح زیر درمیآید:
- خط ۳: تراکنشهای درون یک کانتینر EJB از نوع JTA (تراکنش جاوا API) هستند. با Spring، آنها از نوع RESOURCE_LOCAL بودند.
- خط ۹: پیادهسازی JPA که استفاده میشود، EclipseLink است.
- خطوط ۵–۷: اِنتِتیهای مدیریتشده توسط لایه JPA
- خطوط ۱۱–۱۳: ویژگیهای ارائهدهنده EclipseLink
- خط ۱۲: جداول در هر اجرا ایجاد خواهند شد
ویژگیهای JDBC منبع داده JTA که توسط کانتینر OpenEJB استفاده میشود، توسط فایل پیکربندی زیر [conf/openejb.conf] مشخص خواهد شد:
- خط ۳: شناسه «پایگاه داده پیشفرض JDBC» هنگام کار با یک کانتینر OpenEJB که در خود برنامه تعبیه شده است، استفاده میشود.
- خط ۵: ما از پایگاه داده MySQL [dbpam_eclipselink] استفاده میکنیم
6.1.4. پیادهسازی لایه [DAO] توسط EJB
- کلاسهای پیادهساز لایه [DAO] به EJB تبدیل میشوند. بیایید مثال کلاس [CotisationDao] را در نظر بگیریم:
رابط [ICotisationDao] در نسخه Spring به شرح زیر بود:
EJB این همان رابط را در دو شکل مختلف پیادهسازی خواهد کرد: یک شکل محلی و یک شکل از راه دور. رابط محلی میتواند توسط کلاینتی که در همان JVM اجرا میشود، استفاده شود، در حالی که رابط راه دور میتواند توسط کلاینتی که در یک JVM متفاوت اجرا میشود، استفاده شود.
رابط محلی:
- خط ۶: رابط [ICotisationDaoLocal] از رابط [ICotisationDao] ارث میبرد تا تمام متدهای آن را به کار گیرد. این رابط هیچ متد جدیدی اضافه نمیکند.
- خط ۵: تگ @Local آن را به یک رابط محلی برای EJB تبدیل میکند که آن را پیادهسازی خواهد کرد.
رابط راه دور:
- خط ۶: رابط [ICotisationDaoRemote] از رابط [ICotisationDao] ارث میبرد تا تمام متدهای آن را به کار گیرد. این رابط هیچ متد جدیدی اضافه نمیکند.
- خط ۵: تگ @Remote آن را به یک رابط از راه دور برای EJB تبدیل میکند که آن را پیادهسازی خواهد کرد.
لایه [DAO] توسط کلاسی به نام EJB پیادهسازی شده است که هر دو رابط را پیادهسازی میکند (این امر اجباری نیست):
- خط ۱: تگ @Stateless که کلاس را به یک EJB تبدیل میکند
- خط ۲: anotasyon @TransactionAttribute، که تضمین میکند هر متد در کلاس در داخل یک تراکنش اجرا شود.
- خط ۵: anotasyon @PersistenceContext که EntityManager را از لایه JPA به کلاس [CotisationDao] تزریق میکند. این دقیقاً مشابه چیزی است که در نسخه Spring داشتیم.
وقتی از رابط محلی لایه [DAO] استفاده میشود، کلاینت این رابط در همان JVM اجرا میشود.
![]() |
در مثال بالا، لایههای [metier] و [DAO] اشیاء را بهصورت مرجع مبادله میکنند. وقتی یکی از لایهها شیء مشترک را تغییر میدهد، لایه دیگر این تغییر را مشاهده میکند.
وقتی از رابط دوربرد لایه [DAO] استفاده میشود، کلاینت آن رابط معمولاً در یک JVM دیگر اجرا میشود.
![]() |
در مثال بالا، لایههای [metier] و [DAO] اشیاء را به صورت مقدار مبادله میکنند (سریالسازی شیء مبادله شده). وقتی یک لایه یک شیء مشترک را تغییر میدهد، لایه دیگر تنها در صورتی این تغییر را مشاهده میکند که شیء اصلاح شده برای آن ارسال شود.
6.1.5. پیادهسازی لایه [metier] توسط یک EJB
- کلاسی که لایه [metier] را پیادهسازی میکند، همچنین به یک EJB تبدیل میشود که یک رابط محلی و یک رابط از راه دور را پیادهسازی میکند. رابط اصلی [IMetier] به شرح زیر بود:
ما یک رابط محلی و یک رابط از راه دور را بر اساس رابط قبلی ایجاد میکنیم:
کلاس EJB در لایه [metier] این دو رابط را پیادهسازی میکند:
- خطوط ۱–۲: یک EJB را تعریف میکنند که در آن هر متد درون یک تراکنش اجرا میشود.
- خط ۷: مرجعی به رابط محلی EJB [CotisationDao].
- خط ۶: تذکر @EJB به کانtejینر EJB دستور میدهد تا مرجعی به رابط محلی EJB [CotisationDao] تزریق کند.
- خطوط ۸–۱۱: همین فرایند برای رابطهای محلی EJB، [EmployeDao] و [IndemniteDao] تکرار میشود.
در نهایت، هنگامی که EJB و [Metier] نمونه برداری میشوند، میدانهای روی خطوط ۷، ۹ و ۱۱ با ارجاع به رابطهای محلی سه نمونه EJB در لایه [DAO] مقداردهی اولیه خواهند شد. بنابراین در اینجا فرض میکنیم که لایههای [metier] و [DAO] در همان JVM اجرا خواهند شد.
![]() |
6.1.6. مشتریان EJB
![]() |
در نمودار بالا، برای برقراری ارتباط با لایه [metier]، لایه [ui] باید یک مرجع به رابط دور لایه EJB را از لایه [metier] دریافت کند.
![]() |
در نمودار بالا، برای ارتباط با لایه [metier]، لایه [ui] باید یک مرجع به رابط محلی لایه EJB را از لایه [metier] دریافت کند. روش بهدستآوردن این ارجاعات از یک کانتینر به کانتینر دیگر متفاوت است. برای کانتینر OpenEJB، میتوان رویه زیر را دنبال کرد:
مرجع روی رابط محلی:
- خطوط ۲–۵: کانتینر OpenEJB مقداردهی اولیه میشود.
- خط ۵: یک زمینه JNDI (رابط نامگذاری و دایرکتوری جاوا) وجود دارد که امکان بهدستآوردن ارجاعات برای EJBها را فراهم میکند. هر EJB با نام JNDI مشخص میشود:
- (ادامه)
- برای رابط محلی، «Local» به نام EJB اضافه میشود (خطوط ۷–۹)
- برای رابط محلی، «Local» به نام EJB اضافه میشود
با جاوا EE 5، این قوانین بسته به کانتینر EJB متفاوت هستند. این یک چالش ایجاد میکند. جاوا EE 6 نشانهای JNDI را معرفی کرد که در تمام سرورهای برنامهای قابل حمل است.
کد قبلی ارجاعات به رابطهای محلی EJB را از طریق نامهای JNDI بازیابی میکند. قبلاً اشاره کردیم که این ارجاعات را میتوان از طریق حاشیهنویسی @EJB نیز بهدست آورد. بنابراین ممکن است بخواهیم بنویسیم:
توضیحیه @EJB تنها در صورتی معتبر است که به کلاسی تعلق داشته باشد که توسط کانتینر EJB بارگذاری شده باشد. برای مثال، این مورد برای کلاس [Metier] صدق میکند. با این حال، کد بالا به یک کلاس کنسول تعلق دارد که توسط کانتینر EJB بارگذاری نخواهد شد. بنابراین، ما مجبوریم از نامهای JNDI یا EJB استفاده کنیم.
کد زیر برای به دست آوردن یک مرجع به رابط دور EJB و [Metier] است:
6.2. تمرین عملی
ما پیشنهاد میکنیم که اپلیکیشن NetBeans Spring/Hibernate را به معماری OpenEJB / EclipseLink منتقل کنیم.
پیادهسازی فعلی با استفاده از Spring / Hibernate
![]() |
پیادهسازی مورد نظر با استفاده از OpenEJB / EclipseLink
![]() |
6.2.1. راهاندازی پایگاه داده [dbpam_eclipselink]
اگر وجود ندارد، پایگاه داده MySQL [dbpam_eclipselink] را ایجاد کنید. اگر وجود دارد، تمام جداول آن را حذف کنید. یک اتصال NetBeans به این پایگاه داده همانطور که در بخش 6.2.1 توضیح داده شده است ایجاد کنید.
6.2.2. پیکربندی اولیه پروژه NetBeans
- پروژه Maven با شناسه [mv-pam-spring-hibernate] را بارگذاری کنید
- یک پروژه جدید Maven Java به نام [mv-pam-openejb-eclipselink] و [1] ایجاد کنید
![]() |
- در زبانه [Files] [2]، یک پوشه با نام [conf] [3] زیر ریشه پروژه ایجاد کنید
- فایل زیر را در این پوشه قرار دهید: [openejb.conf] [4]:
![]() |
- پوشه [src / main/ resources/ META-INF] [5] را ایجاد کنید
- فایلهای زیر را در آن قرار دهید: [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">
<!--ارائهدهنده JPA است EclipseLink -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- اشیاء Jpa -->
<class>jpa.Cotisation</class>
<class>jpa.Employe</class>
<class>jpa.Indemnite</class>
<!-- ویژگیهای ارائهدهنده EclipseLink -->
<properties>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>
- خط ۱۲: لاگهای تفصیلی از EclipseLink درخواست میشود،
- خط ۱۳: جداول هنگام نمونهسازی لایه JPA ایجاد خواهند شد،
- کتابخانههای OpenEJB، EclipseLink و درایور JDBC از MySQL را به فایل [pom.xml] در پروژه اضافه کنید:
<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>
- خطوط ۱۸–۲۲: وابستگی OpenEJB،
- خطوط ۳۰–۳۹: وابستگیهای EclipseLink،
- خطوط ۴۱–۴۴: وابستگی درایور JDBC به MySQL
6.2.3. پورت کردن لایه [DAO]
ما لایه [DAO] را با کپی کردن بستهها از پروژه [mv-pam-spring-hibernate] به پروژه [mv-pam-openejb-eclipselink] منتقل خواهیم کرد.
- پکیجهای [dao, exception, jpa] را کپی کنید
![]() |
خطاهای گزارششده در بالا به این دلیل است که لایه کپیشده [DAO] از Spring استفاده میکند و کتابخانههای Spring دیگر بخشی از پروژه نیستند.
6.2.3.1. EJB [CotisationDao]
ما در حال ایجاد رابطهای محلی و راه دور برای EJB و [CotisationDao] آینده هستیم:
رابط محلی ICotisationDaoLocal:
برای دریافت بستههای صحیح import، [clic droit sur le code / Fix Imports] را اجرا کنید.
رابط راه دور ICotisationDaoRemote:
سپس کلاس [CotisationDao] را اصلاح میکنیم تا آن را به EJB تبدیل کنیم:
import که این کلاس روی فریمورک Spring تولید میکرد دیگر وجود ندارد. یک [Clean and Build] برای پروژه تولید کنید:
![]() |
در [1]، دیگر هیچ خطایی در کلاس [CotisationDao] وجود ندارد.
6.2.3.2. EJB، [EmployeDao] و [IndemniteDao]
ما همین رویه را برای سایر عناصر لایه [DAO] تکرار میکنیم:
- رابطهای IEmployeDaoLocal و IEmployeDaoRemote که از IEmployeDao مشتق شدهاند
- EJB و EmployeDao که این دو رابط را پیادهسازی میکنند
- رابطهای IIndemniteDaoLocal و IIndemniteDaoRemote، مشتقشده از IIndemniteDao
- EJB و IndemniteDao، که این دو رابط را پیادهسازی میکنند
پس از انجام این کار، دیگر هیچ خطایی در پروژه [2] وجود ندارد.
6.2.3.3. کلاس [PamException]
کلاس [PamException] همانطور که بود باقی میماند، با یک تفاوت جزئی:
خط ۵ اضافه شده است. برای دریافت import صحیح، آن را به [Fix imports] تغییر دهید.
برای درک حاشیهنویسی روی خط ۵، مهم است به خاطر داشته باشید که هر متد در کلاس EJB در لایه [DAO] ما:
- درون یک تراکنش که توسط کانتینر EJB آغاز و پایان مییابد، اجرا میشود
- به محض اینکه مشکلی پیش بیاید، یک استثنا از نوع [PamException] پرتاب میکند
![]() |
وقتی لایه [metier] متد M از لایه [DAO] را فراخوانی میکند، این فراخوانی توسط کانتینر EJB رهگیری میشود. گویی یک کلاس واسط بین لایه [metier] و لایه [DAO] – که در اینجا [Proxy EJB] نامیده میشود – وجود دارد که تمام فراخوانیهای لایه [DAO] را رهگیری میکند. وقتی فراخوانی متد M در لایه [DAO] رهگیری میشود، پروکسی EJB یک تراکنش را آغاز میکند و سپس کنترل را به متد M در لایه [DAO] واگذار میکند که سپس در آن تراکنش اجرا میشود. روش M ممکن است با یا بدون استثنا خاتمه یابد.
- اگر متد M بدون خطا به پایان برسد، اجرای کد به پروکسی EJB بازمیگردد که با commit کردن تراکنش از طریق commit، آن را خاتمه میدهد. سپس جریان اجرایی به متد فراخوانیکننده در لایه [metier] بازمیگردد.
- اگر متد M با یک استثنا خاتمه یابد، کنترل به پروکسی EJB بازمیگردد، که تراکنش را از طریق rollback باطل کرده و آن را خاتمه میدهد. علاوه بر این، این استثنا را در یک نوع EJBException محصور میکند. کنترل سپس به متد فراخوانیکننده لایه [metier] بازگردانده میشود که در نتیجه یک EJBException دریافت میکند. تفسیر متنی در خط ۵ بالا از این پوشانندگی جلوگیری میکند. لایه [metier] در نتیجه یک PamException دریافت خواهد کرد. علاوه بر این، ویژگی rollback=true به پروکسی EJB دستور میدهد که وقتی یک PamException دریافت میکند، باید تراکنش را بازگردانَد.
6.2.3.4. آزمایش لایه [DAO]
لایه [DAO] ما که توسط EJB پیادهسازی شده است، آماده آزمایش است. ما با کپی کردن بسته [dao] از [Test Packages] در پروژه [mv-pam-springhibernate] به پروژه در حال توسعه [1] شروع میکنیم:
![]() |
ما فقط کلاس تست [JUnitInitDB] را که پایگاه داده را با برخی از دادههای [2] اولیه میکند، نگه میداریم. ما نام کلاس [ JUnitInitDbLocal] را به [3] تغییر میدهیم. کلاس [JUnitInitDBLocal] از رابط محلی EJB در لایه [DAO] استفاده خواهد کرد.
ابتدا، کلاس [JUnitInitDBLocal] را به شرح زیر اصلاح میکنیم:
- خطوط ۳–۵: ارجاع به رابطهای محلی EJB در لایه [DAO]
- خط ۷: @BeforeClass متدی را که هنگام شروع تست JUnit اجرا میشود، نشانهگذاری میکند
- خطوط ۱۰–۱۳: инициалиزهسازی کانتینر OpenEJB. این инициалиزهسازی اختصاصی است و برای هر کانتینر EJB متفاوت است.
- خط ۱۳: یک زمینه JNDI (رابط نامگذاری و دایرکتوری جاوا) وجود دارد که دسترسی به EJB را از طریق نامها فراهم میکند. در OpenEJB، رابط محلی یک EJB E توسط ELocal و رابط راه دور توسط ERemote تعیین میشود.
- خطوط ۱۵–۱۷: از زمینه JNDI خواسته شده است مرجعی به رابطهای محلی EJB و [EmployeDao, CotisationDao, IndemniteDao] ارائه دهد.
![]() |
پروژه را بسازید، در صورت لزوم سرور MySQL را راهاندازی کنید و تست JUnitInitDBLocal را اجرا کنید. لطفاً توجه داشته باشید که فایل [persistence.xml] طوری پیکربندی شده است که در هر اجرا، جداول را دوباره ایجاد کند. قبل از اجرای تست، توصیه میشود هرگونه جدول را از پایگاههای داده MySQL و [dbpam_eclipselink] حذف کنید.
![]() |
- در [1]، در برگه [Services]، جداول را از اتصال NetBeans که در بخش 6.2.1 ایجاد شده است، حذف کنید.
- در [2]، پایگاه داده [dbpam_eclipselink] دیگر هیچ جدولی ندارد
- در [3]، پروژه ساخته میشود
- در [4]، تست JUnitInitDBLocal اجرا میشود
![]() |
- در [5]، تست با موفقیت انجام شد
- در [6]، اتصال NetBeans تازه میشود
- در [7]، چهار جدولی که توسط لایه JPA ایجاد شدهاند نمایش داده میشوند. هدف از این تست، پر کردن آنها بود. محتوای یکی از آنها نمایش داده میشود
![]() |
- در [8]، محتویات جدول [EMPLOYES]
کانتینر OpenEJB لاگها را در کنسول نمایش داد:
- خطوط ۲–۳: دو نام JNDI از EJB و [CotisationDaoLocal]،
- خطوط ۴–۵: دو نام JNDI از EJB و [CotisationDaoRemote]،
- سطور ۷–۸: دو نام JNDI از EJB و [EmployeDaoLocal]،
- سطور ۹–۱۰: دو نام JNDI از EJB و [EmployeDaoRemote],
- سطور ۱۲–۱۳: دو نام JNDI از EJB و [IndemniteDaoLocal],
- سطور 14–15: دو نام JNDI از EJB و [EmployeDaoRemote].
ما همان آزمایش را تکرار میکنیم، این بار با استفاده از رابط دور EJB.
![]() |
در [1]، کلاس [JUnitInitDBLocal] به [JUnitInitDBRemote] کپی/پیست شده است. در این کلاس، ما رابطهای محلی را با رابطهای از راه دور جایگزین میکنیم:
پس از انجام این کار، میتوان کلاس تست جدید را اجرا کرد. پیش از آن، با استفاده از اتصال NetBeans با شناسه [dbpam_eclipselink]، جداول را از پایگاه داده [dbpam_eclipselink] حذف کنید.
![]() |
با استفاده از اتصال NetBeans [dbpam_eclipselink]، بررسی کنید که پایگاه داده پر شده است.
6.2.4. پورت کردن لایه [metier]
ما لایه [metier] را با کپی کردن بستهها از پروژه [mv-pam-spring-hibernate] به پروژه [mv-pam-openejb-eclipselink] منتقل خواهیم کرد.
![]() |
خطاهای گزارششده در بالا ([1]) به این دلیل است که لایه کپیشده [metier] از Spring استفاده میکند و کتابخانههای Spring دیگر بخشی از پروژه نیستند.
6.2.4.1. EJB [Metier]
ما همان رویهای را که برای EJB و [CotisationDao] توضیح داده شده است، دنبال میکنیم. ابتدا، در [2]، ما رابطهای محلی و راه دوری را برای EJB و [Metier] آینده ایجاد میکنیم. هر دو از رابط اولیه [IMetier] مشتق شدهاند.
پس از انجام این کار، در [3] کلاس [Metier] را اصلاح میکنیم تا به EJB تبدیل شود:
- خط ۱: anotation @Stateless کلاس را به EJB تبدیل میکند
- خط ۲: هر متد در کلاس در داخل یک تراکنش اجرا خواهد شد
- خط ۳: کلاس EJB [Metier] هر دو رابط محلی و راه دوری را که به تازگی تعریف کردهایم پیادهسازی میکند
- خط ۷: EJB از [Metier] از طریق رابط محلی آن استفاده خواهد کرد. این بدان معناست که لایههای [metier] و [DAO] باید در همان JVM اجرا شوند.
- خط ۶: حاشیهنویسی @EJB تضمین میکند که خود کانتینر EJB ارجاع را به رابط محلی EJB [CotisationDao] تزریق کند. رویکرد دیگری که با آن مواجه شدهایم، استفاده از یک زمینه JNDI است.
- خطوط ۸–۱۱: همان مکانیزم برای دو نمونه دیگر EJB در لایه [DAO] استفاده میشود.
6.2.4.2. آزمایش لایه [metier]
لایه [metier] ما که توسط EJB پیادهسازی شده است، اکنون قابل آزمایش است. ما با کپی کردن بسته [metier] از [Test Packages] در پروژه [mv-pam-spring-hibernate] به پروژه در حال توسعه [1] شروع میکنیم:
![]() |
- به [1]، نتیجهٔ کپی
- به [2]؛ تست اول حذف شد
- در [3]، تست باقیمانده به [JUnitMetierLocal] تغییر نام داده میشود
کلاس [JUnitMetierLocal] به صورت زیر در میآید:
- خط ۴: مرجعی به رابط محلی EJB [Metier]
- خطوط ۸–۱۲: پیکربندی کانتینر OpenEJB، مشابه پیکربندی انجامشده در تست لایه [DAO]
- خطوط ۱۵–۱۹: زمینه JNDI از خط ۱۲ پرسوجو میشود، برای ارجاع به سه نمونه EJB در لایه [DAO] و به نمونه EJB در لایه [metier]. EJB در لایه [DAO] برای راهاندازی پایگاه داده استفاده خواهد شد، در حالی که EJB در لایه [metier] برای انجام آزمونهای محاسبه حقوق و دستمزد استفاده خواهد شد.
اجرای تست [JUnitMetierLocal] نتیجه زیر را تولید میکند، [1]:
![]() |
در [2]، ما [JUnitMetierLocal] را به عنوان [JUnitMetierRemote] برای آزمایش رابط دور EJB و [Metier] کپی میکنیم. کد [JUnitMetierRemote] برای استفاده از این رابط دور تغییر یافته است. سایر موارد بدون تغییر باقی ماندهاند.
- خطوط ۴ و ۱۹: از رابط دور EJB و [Metier] استفاده میشود.
- خطوط ۱۵–۱۷: رابطهای دور لایه [DAO] استفاده میشوند
- خطوط ۳۴–۳۵: از آنجا که در رابطهای از راه دور، اشیایی که بین کلاینت و سرور مبادله میشوند به صورت مقدار (value) ارسال میشوند، باید نتیجه بازگردانده شده توسط متد create(Indemnite i) دریافت شود. این کار در رابطهای محلی ضروری نبود، زیرا در آنجا اشیاء به صورت مرجع (reference) ارسال میشوند.
پس از انجام این کار، پروژه قابل ساختن است و تست [JUnitMetierRemote] قابل اجرا خواهد بود:
![]() |
6.2.5. پورت کردن لایه [console]
ما لایه [console] را با کپی کردن پکیجها از پروژه [mv-pam-spring-hibernate] به پروژه [mv-pam-openejb-eclipselink] منتقل خواهیم کرد.
![]() |
خطاهای گزارششده در بالا برای [1] به این دلیل است که لایه کپیشده [metier] از Spring استفاده میکند و کتابخانههای Spring دیگر بخشی از پروژه نیستند. در [2]، کلاس [Main] به [MainLocal] تغییر نام داده شده است. این کلاس از رابط محلی EJB [Metier] استفاده خواهد کرد.
کد کلاس [MainLocal] به شرح زیر تغییر میکند:
تغییرات در خطوط ۱۳ تا ۲۵ انجام شده است. به این ترتیب، ارجاع به لایه [metier] تغییر داده شده است (خطوط ۱۷ تا ۲۲). ما کد جدید را توضیح نمیدهیم، زیرا قبلاً در مثالهای قبلی پوشش داده شده است. پس از اعمال این تغییرات، پروژه دیگر هیچ خطایی ندارد (به [3] مراجعه کنید).
ما پروژه را برای اجرا با آرگومانهای زیر پیکربندی میکنیم: [1]:
![]() |
برای اینکه برنامه کنسولی بهطور عادی اجرا شود، باید در پایگاه داده داده وجود داشته باشد. برای این کار، باید فایل [META-INF/persistence.xml] را اصلاح کنیم:
<?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">
<!-- ارائهدهنده JPA است EclipseLink -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- اشیاء Jpa -->
<class>jpa.Cotisation</class>
<class>jpa.Employe</class>
<class>jpa.Indemnite</class>
<!--ویژگیهای ارائهدهنده EclipseLink -->
<properties>
<property name="eclipselink.logging.level" value="FINE"/>
<!--
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
-->
</properties>
</persistence-unit>
</persistence>
خط ۱۴ که باعث میشد جداول پایگاه داده در هر اجرا دوباره ایجاد شوند، غیرفعال شده است. برای اینکه این تغییر اعمال شود، پروژه باید دوباره ساخته شود (پاکسازی و ساخت). پس از انجام این کار، برنامه قابل اجرا خواهد بود. اگر همه چیز به درستی پیش برود، خروجی کنسول مشابه موارد زیر خواهد بود:
در اینجا، از رابط محلی لایه [metier] استفاده کردهایم. اکنون در یک کلاس کنسول دوم از رابط راه دور آن استفاده میکنیم:
![]() |
در [1]، کلاس [MainLocal] به صورت [MainRemote] کپی شده است. کد [MainRemote] اصلاح شده است تا از رابط دوربرد لایه [metier] استفاده کند:
تغییراتی در خطوط ۲ و ۸ اعمال شده است. پروژه [2] برای اجرای کلاس [MainRemote] پیکربندی شده است. اجرای آن نتایج مشابهی با قبل دارد.
6.3. Conclusion
ما نشان دادهایم چگونه یک معماری Spring/Hibernate را به معماری OpenEJB/EclipseLink مهاجرت کنیم.
معماری Spring/Hibernate
![]() |
معماری OpenEJB / EclipseLink
![]() |
فرآیند انتقال بهخوبی پیش رفت زیرا برنامهٔ اصلی بهصورت لایهلایه ساختار یافته بود. این نکتهٔ مهمی است که باید درک شود.




























