4. خدمة الويب J2EE الخاصة بالمواعيد
لنعد إلى بنية التطبيق المراد إنشاؤه:
![]() |
نركز في هذا الجزء على إنشاء خدمة الويب J2EE [1] التي يتم تشغيلها على خادم Sun / Glassfish.
4.1. قاعدة البيانات
قاعدة البيانات التي سنسميها [dbrdvmedecins] هي قاعدة بيانات MySQL5 تحتوي على أربع جداول:

4.1.1. الجدول [MEDECINS]
تحتوي على معلومات عن الأطباء الذين يديرهم التطبيق [RdvMedecins].
![]() | ![]() |
- ID: الرقم الذي يحدد هوية الطبيب - المفتاح الأساسي للجدول
- VERSION: الرقم الذي يحدد إصدار السطر في الجدول. يتم زيادة هذا الرقم بمقدار 1 في كل مرة يتم فيها إجراء تعديل على السطر.
- NOM: اسم الطبيب
- PRENOM: اسمه الأول
- TITRE: لقبه (الآنسة، السيدة، السيد)
4.1.2. الجدول [CLIENTS]
يتم تسجيل مرضى الأطباء المختلفين في الجدول [CLIENTS]:
![]() | ![]() |
- ID: الرقم التعريفي للعميل - المفتاح الأساسي للجدول
- VERSION: الرقم الذي يحدد إصدار السطر في الجدول. يتم زيادة هذا الرقم بمقدار 1 في كل مرة يتم فيها إجراء تعديل على السطر.
- NOM: اسم العميل
- PRENOM: اسمه الأول
- TITRE: لقبه (الآنسة، السيدة، السيد)
4.1.3. الجدول [CRENEAUX]
تسرد هذه الجدول الفترات الزمنية التي يمكن فيها استخدام RV:
![]() |
![]() |
- ID: الرقم الذي يحدد الفترة الزمنية - المفتاح الأساسي للجدول (السطر 8)
- VERSION: الرقم الذي يحدد إصدار السطر في الجدول. يتم زيادة هذا الرقم بمقدار 1 في كل مرة يتم فيها إجراء تعديل على السطر.
- ID_MEDECIN: الرقم الذي يحدد الطبيب الذي ينتمي إليه هذا الموعد – مفتاح خارجي في العمود MEDECINS (ID).
- HDEBUT: وقت بدء الفترة الزمنية
- MDEBUT: الدقائق الأولى للفترة
- HFIN: ساعة انتهاء الفترة الزمنية
- MFIN: الدقائق التي تنتهي فيها الفترة الزمنية
يشير السطر الثاني من الجدول [CRENEAUX] (انظر [1] أعلاه)، على سبيل المثال، إلى أن الفترة رقم 2 تبدأ في الساعة 8:20 وتنتهي في الساعة 8:40، وتخص الطبيبة رقم 1 (السيدة ماري PELISSIER).
4.1.4. الجدول [RV]
تسرد الجدول RV المواعيد المحددة لكل طبيب:
![]() |
- ID: الرقم الذي يحدد RV بشكل فريد – المفتاح الأساسي
- JOUR: يوم RV
- ID_CRENEAU: الفترة الزمنية لـ RV – مفتاح خارجي في الحقل [ID] من الجدول [CRENEAUX] – يحدد في آن واحد الفترة الزمنية والطبيب المعني.
- ID_CLIENT: رقم العميل الذي تم الحجز لصالحه – مفتاح خارجي في الحقل [ID] في الجدول [CLIENTS]
يحتوي هذا الجدول على قيد « » يضمن تفرد قيم الأعمدة المرتبطة (JOUR، ID_CRENEAU):
إذا كان أحد صفوف الجدول [RV] يحتوي على القيمة (JOUR1، ID_CRENEAU1) للأعمدة (JOUR، ID_CRENEAU)، فلا يمكن أن تظهر هذه القيمة في أي مكان آخر. وإلا، فهذا يعني أنه تم تسجيل قيمتين لـ RV في نفس الوقت لنفس الطبيب. من منظور برمجة Java، يقوم برنامج التشغيل JDBC الخاص بقاعدة البيانات بتشغيل برنامج SQLException عند حدوث هذه الحالة.
السطر الذي يحتوي على القيمة 3 لـ id (انظر [1] أعلاه) يعني أنه تم حجز موعد RV للفترة رقم 20 والعميل رقم 4 في 23/08/2006. يُظهر الجدول [CRENEAUX] أن الموعد رقم 20 يتوافق مع الفترة الزمنية من الساعة 16:20 إلى 16:40، وهو مخصص للطبيبة رقم 1 (السيدة ماري PELISSIER). توضح لنا الجدولة [CLIENTS] أن العميل رقم 4 هي الآنسة بريجيت BISTROU.
4.2. إنشاء قاعدة البيانات
قم بإنشاء قاعدة البيانات MySql [dbrdvmedecins] باستخدام الأداة التي تختارها. لإنشاء الجداول وتعبئتها، يمكنك استخدام البرنامج النصي [createbd.sql] الذي سيتم تزويدك به. ومحتواه كما يلي:
4.3. عناصر بنية جانب الخادم
لنعد إلى بنية التطبيق المراد إنشاؤه:
![]() |
على جانب الخادم، سيتكون التطبيق من:
- من طبقة JPA تتيح العمل مع BD عن طريق كائنات
- وEJB مكلفة بإدارة العمليات مع طبقة JPA
- خدمة ويب مسؤولة عن عرض واجهة EJB للعملاء البعيدين في شكل خدمة ويب.
العنصران (ب) و(ج) ينفذان طبقة [dao] الموضحة في المخطط السابق. ومن المعروف أن التطبيق يمكنه الوصول إلى كائن EJB بعيد عبر بروتوكولي RMI وJNDI. في الواقع العملي، يقتصر ذلك على عملاء Java. تستخدم خدمة الويب بروتوكول اتصال موحدًا تنفذه لغات برمجة متنوعة: .NET، وPHP، وC++، ... وهذا ما نريد إظهاره هنا باستخدام عميل .NET.
للحصول على مقدمة موجزة عن خدمات الويب، يمكن قراءة الدرس [ref1]، الفقرة 14، الصفحة 109.
يمكن تنفيذ خدمة الويب بطريقتين:
- عن طريق فئة مُعلَّمة بـ @WebService تُنفَّذ في حاوية ويب
![]() |
- عن طريق كائن EJB مُعلَّم بـ @WebService والذي يتم تنفيذه في حاوية EJB
![]() |
![]() |
سنستخدم هنا الحل الأول:
في الدورة التدريبية [ref1]، الفقرة 14، الصفحة 109، يوجد مثال يستخدم الحل الثاني.
4.4. تكوين Hibernate لـ s على خادم Glassfish
اعتمادًا على إصداره، قد لا يحتوي خادم Glassfish V2 المرفق مع NetBeans على مكتبات Hibernate التي تحتاجها طبقة JPA/Hibernate. إذا اكتشفت خلال متابعة هذا البرنامج التعليمي أن خادم Glassfish لا يوفر لك تنفيذ JPA/Hibernate، أو إذا ظهرت استثناء عند نشر الخدمات يشير إلى عدم العثور على مكتبات Hibernate، فيجب عليك إضافة المكتبات إلى المجلد [<glassfish>/domains/domain1/lib/ext] ثم إعادة تشغيل خادم Glassfish:
![]() |
|
توجد مكتبات Hibernate في ملف zip المرفق بالبرنامج التعليمي.
4.5. أدوات الإنشاء التلقائي في NetBeans
لنعد إلى البنية التي يتعين علينا إنشاؤها:
![]() |
باستخدام NetBeans، يمكن إنشاء الطبقة [JPA] والطبقة [Ejb] التي تتحكم في الوصول إلى الكيانات JPA التي تم إنشاؤها تلقائيًا. من المفيد التعرف على طرق الإنشاء التلقائي هذه لأن الكود الذي يتم إنشاؤه يقدم إرشادات قيّمة حول كيفية كتابة الكيانات JPA أو كود EJB الذي يستخدمها.
نصف الآن بعض أدوات الإنشاء التلقائي هذه. لفهم الكود الذي تم إنشاؤه، يجب أن يكون لدى القارئ معرفة جيدة بالكيانات JPA و[ref1] وEJB و[ref2].
إنشاء اتصال NetBeans بقاعدة البيانات
- قم بتشغيل SGBD و MySQL 5 حتى يصبح BD متاحًا
- إنشاء اتصال NetBeans بقاعدة البيانات [dbrdvmedecins]
![]() |
- في علامة التبويب [Files]، ضمن الفرع [Databases] [1]، حدد برنامج التشغيل Jdbc MySQL [2]
- ثم حدد الخيار [3] «Connect Using» الذي يتيح إنشاء اتصال بقاعدة بيانات MySQL
- في [4]، أدخل المعلومات المطلوبة
- ثم قم بالتأكيد في [5]
![]() |
- في [6]، يتم إنشاء الاتصال. ويمكن رؤية الجداول الأربعة لقاعدة البيانات المتصلة.
إنشاء مشروع EJB
![]() |
- إلى [1]، قم بإنشاء تطبيق جديد، ووحدة EJB
- في [2]، اختر الفئة [Java EE] وفي [3] اختر النوع [EJB Module]
![]() |
- في [4] اختر مجلدًا للمشروع وفي [5] قم بتسميته - ثم أكمل المعالج
- في [6] المشروع الذي تم إنشاؤه
إضافة مورد JDBC إلى خادم Glassfish
سنقوم بإضافة مورد JDBC إلى خادم Glassfish.
![]() |
![]() |
- في علامة التبويب [Services]، قم بتشغيل خادم Glassfish [2, 3]
- في علامة التبويب [Projects]، انقر بزر الماوس الأيمن على مشروع Ejb وفي [5] حدد الخيار [New / Other] الذي يسمح بإضافة عنصر إلى المشروع.

- في [6]، حدد الفئة [Glassfish]، ثم في [7] حدد أنك تريد إنشاء مورد JDBC عن طريق تحديد النوع [JDBC Resource]
- في [8]، حدد أن هذا المورد JDBC سيستخدم مجموعة اتصالاته الخاصة
- في [9]، قم بتسمية المورد JDBC
- في [10]، انتقل إلى الخطوة التالية
![]() |
- في [11]، يتم تحديد خصائص مجموعة اتصالات المورد JDBC
- في [12]، قم بتسمية مجموعة الاتصالات
- في [13]، اختر اتصال NetBeans [dbrdvmedecins] الذي تم إنشاؤه مسبقًا
- في [14]، انتقل إلى الخطوة التالية
- في [15]، لا يوجد عادةً ما يستدعي التغيير في هذه الصفحة. تم استخلاص خصائص الاتصال بقاعدة البيانات MySQL [dbrdvmedecins] من خصائص اتصال NetBeans [dbrdvmedecins] الذي تم إنشاؤه مسبقًا
- في [16]، انتقل إلى الخطوة التالية
![]() |
- إلى [17]، واحتفظ بالقيم الافتراضية المقترحة
- إلى [18]، ثم أكمل المعالج. يقوم المعالج بإنشاء الملف [sun-resources.xml] و[19] الذي يكون محتواه كما يلي:
يحتوي الملف أعلاه على جميع المعلومات التي تم إدخالها في المعالج بتنسيق XML. وسيتم استخدامه بواسطة IDE NetBeans لمطالبة خادم Glassfish بإنشاء المورد "jdbc/dbrdvmedecins" المحدد في السطر 4.
إنشاء وحدة ثبات
تقوم وحدة الاستمرارية [persistence.xml] بتكوين الطبقة JPA: فهي تحدد التنفيذ JPA المستخدم (Toplink، Hibernate، ...) وتقوم بتكوينه.
![]() |
![]() |
- في [1]، انقر بزر الماوس الأيمن على مشروع Ejb واختر [New / Other] في [2]
- في [3]، حدد الفئة [Persistence] ثم في [4]، حدد أنك تريد إنشاء وحدة استمرارية JPA
![]() |
- في [5]، قم بتسمية وحدة الاستمرارية التي تم إنشاؤها
- في [6]، اختر [Hibernate] كتنفيذ لـ JPA
- في [7]، حدد مورد Glassfish "jdbc/dbrdvmedecins" الذي تم إنشاؤه للتو
- في [8]، حدد أنه لا يجب اتخاذ أي إجراء على قاعدة البيانات عند إنشاء مثيل الطبقة JPA
- قم بإنهاء المعالج
- في [9]، الملف [persistence.xml] الذي أنشأه المساعد
محتواه كما يلي:
مرة أخرى، يعيد الملف XML المعلومات التي تم إدخالها في المساعد. هذا الملف غير كافٍ للعمل مع قاعدة البيانات MySQL5 "dbrdvmedecins". يجب أن نحدد لـ Hibernate نوع ملف SGBD المطلوب إدارته. وسيتم ذلك لاحقًا.
إنشاء الكيانات JPA
![]() |
![]() |
![]() |
- في [1]، انقر بزر الماوس الأيمن على المشروع، ثم في [2] اختر الخيار [New / Other]
- في [3]، حدد الفئة [Persistence] ثم في [4]، حدد أنك تريد إنشاء كيانات JPA من قاعدة بيانات موجودة.
![]() |
- في [5]، حدد المصدر JDBC "jdbc/dbrdvmedecins" الذي أنشأناه
- في [6]، الجداول الأربعة لقاعدة البيانات المرتبطة
- في [7,8]، قم بتضمينها جميعًا في عملية إنشاء الكيانات JPA
- في [9]، ومتابعة المعالج
![]() |
- في [10]، الكيانات JPA التي سيتم إنشاؤها
- إلى [11]، قم بتسمية حزمة الكيانات JPA
- إلى [12]، واختيار نوع Java الذي سيقوم بتغليف قوائم الكائنات التي تُرجعها الطبقة JPA
- إنهاء المعالج
- في [13]، الكيانات الأربعة JPA التي تم إنشاؤها، واحد لكل جدول في قاعدة البيانات.
فيما يلي، على سبيل المثال، كود الكيان [Rv] الذي يمثل سطرًا من الجدول [rv] في قاعدة البيانات [dbrdvmedecins].
إنشاء طبقة EJB للوصول إلى الكيانات JPA
![]() |
![]() |
- في [1]، انقر بزر الماوس الأيمن على المشروع وفي [2]، حدد الخيار [New / Other]
- في [3]، حدد الفئة [Persistence] ثم في [4] النوع [Session Beans for Entity Classes]
![]() |
- في [5]، تظهر الكيانات JPA التي تم إنشاؤها مسبقًا
- في [6]، حددها جميعًا
- في [7]، تم تحديدها
- في [8]، تابع المعالج
![]() |
- في [9]، قم بتسمية حزمة EJB التي سيتم إنشاؤها
- في [10]، حدد أن EJBs يجب أن تنفذ واجهة محلية وواجهة بعيدة في آن واحد
- إنهاء المساعد
- في [11]، EJB التي تم إنشاؤها
فيما يلي، على سبيل المثال، كود EJB الذي يدير الوصول إلى الكيان [Rv]، وبالتالي إلى الجدول [rv] في قاعدة البيانات [dbrdvmedecins]:
كما ذكرنا سابقًا، يمكن أن يكون التوليد التلقائي للكود مفيدًا جدًّا لبدء مشروع ما والتدرب على الكيانات JPA وEJB. في ما يلي، سنقوم بإعادة كتابة الطبقات JPA و EJB باستخدام كودنا الخاص، لكن القارئ سيجد فيها المعلومات التي استعرضناها للتو في عملية الإنشاء التلقائي للطبقات.
4.6. مشروع NetBeans للوحدة النمطية EJB
نقوم بإنشاء وحدة EJB جديدة فارغة (انظر الفقرة 4.5):
![]() |
- تضم الحزمة [rdvmedecins.entites] كيانات طبقة JPA
- الحزمة [rdvmedecins.dao] تُنفِّذ EJB للطبقة [dao]
- الحزمة [rdvmedecins.exceptions] تُنفِّذ فئة استثناء خاصة بالتطبيق
فيما يلي، نفترض أن القارئ قد اتبع جميع الخطوات الواردة في الفقرة 4.5. وسيتعين عليه إعادة بعضها.
4.6.1. تكوين الطبقة JPA
دعونا نستعرض بنية تطبيقنا العميل/الخادم:
![]() |
مشروع NetBeans:
![]() |
يتم تكوين الطبقة [JPA] بواسطة الملفين [persistence.xml] و [sun-resources.xml] المذكورين أعلاه. يتم إنشاء هذين الملفين بواسطة المعالجات التي سبق أن تناولناها:
- تم وصف عملية إنشاء الملف [sun-resources.xml] في الفقرة 4.5.
- وقد تم وصف إنشاء الملف [persistence.xml] في الفقرة 4.5.
يجب تعديل الملف [persistence.xml] الذي تم إنشاؤه على النحو التالي:
- السطر 3: نوع المعاملات هو JTA: ستتم إدارة المعاملات بواسطة حاوية Ejb3 في Glassfish
- السطر 4: يتم استخدام تطبيق JPA / Hibernate. ولهذا الغرض، تمت إضافة مكتبة Hibernate إلى خادم Glassfish (انظر الفقرة 4.4).
- السطر 5: مصدر البيانات JTA الذي تستخدمه طبقة JPA يحمل الاسم JNDI «jdbc/dbrdvmedecins».
- السطر 8: لا يتم إنشاء هذا السطر تلقائيًا. يجب إضافته يدويًّا. وهو يُشير إلى Hibernate بأن SGBD المستخدم هو MySQL5.
يتم تكوين مصدر البيانات "jdbc/dbrdvmedecins" في الملف [sun-resources.xml] التالي:
- الأسطر 8-10: خصائص Jdbc لمصدر البيانات (عنوان URL لقاعدة البيانات، واسم المستخدم وكلمة المرور). قاعدة البيانات MySQL dbrdvmedecins هي تلك الموصوفة في الفقرة 4.1.
- السطر 7: خصائص مجموعة الاتصالات المرتبطة بمصدر البيانات هذا
4.6.2. كيانات الطبقة JPA
لنتذكر بنية تطبيقنا العميل/الخادم:
![]() |
مشروع NetBeans:
![]() |
تقوم الحزمة [rdvmedecins.entites] بتنفيذ الطبقة [Jpa].
لقد رأينا في الفقرة 4.5 كيفية إنشاء كيانات JPA تلقائيًا لتطبيق ما. لن نستخدم هذه التقنية هنا، بل سنقوم بتعريف الكيانات بأنفسنا. ومع ذلك، ستتضمن هذه الكيانات جزءًا كبيرًا من الكود الذي تم إنشاؤه في الفقرة 4.5. ونرغب هنا في أن تكون الكيانات [Medecin] و [Client] فئات فرعية لفئة [Personne].
تُستخدم فئة «Personne» لتمثيل الأطباء والعملاء:
- السطر 3: تجدر الإشارة إلى أن الفئة [Personne] ليست كيانًا (@Entity) بحد ذاتها. ستكون الفئة الأم للكيانات. يشير التعليق التوضيحي @MappedSuperClass إلى هذه الحالة.
تغلف الكيان [Client] صفوف الجدول [clients]. وهي مشتقة من الفئة السابقة [Personne]:
- السطر 3: الفئة [Client] هي كيان JPA
- السطر 4: وهي مرتبطة بالجدول [clients]
- السطر 5: وهي مشتقة من الفئة [Personne]
الكيان [Medecin] الذي يغلف صفوف الجدول [medecins] يتبع نفس النموذج:
تضم الكيان [Creneau] صفوف الجدول [creneaux]:
- الصفوف 15-17 تمثل العلاقة «واحد إلى عدة» الموجودة بين الجدول [creneaux] والجدول [medecins] في قاعدة البيانات.
تضم الكيان [Rv] الصفوف الموجودة في الجدول [rv]:
- الصفوف 15-17 تمثل العلاقة «واحد إلى عدة» الموجودة بين الجدول [rv] والجدول [clients] في قاعدة البيانات، بينما تمثل الصفوف 18-20 العلاقة «واحد إلى عدة» القائمة بين الجدول [rv] والجدول [creneaux]
4.6.3. فئة الاستثناء
![]() |
فئة الاستثناء [RdvMedecinsException] الخاصة بالتطبيق هي كما يلي:
- السطر 6: الفئة مشتقة من الفئة [RuntimeException]. وبالتالي، لا يفرض المُجمِّع معالجتها باستخدام try / catch.
- السطر 5: التوضيح @ApplicationException يضمن ألا يتم «ابتلاع» الاستثناء بواسطة استثناء من النوع [EjbException].
لفهم التعليق التوضيحي @ApplicationException، لنعد إلى البنية المستخدمة على جانب الخادم:
![]() |
سيتم إطلاق الاستثناء من النوع [RdvMedecinsException] بواسطة طرق EJB الخاصة بالطبقة [dao] داخل حاوية Ejb3، وستقوم الحاوية باعتراضه. وبدون التعليق التوضيحي @ApplicationException، تقوم الحاوية Ejb3 بتغليف الاستثناء الذي حدث في استثناء من النوع [EjbException] وإعادة إطلاقه. قد لا نرغب في هذا التغليف ونسمح بخروج استثناء من النوع [RdvMedecinsException] من الحاوية Ejb3. وهذا ما تتيحه العلامة @ApplicationException. من ناحية أخرى، يشير السمة (rollback=true) في هذا التعليق التوضيحي إلى حاوية Ejb3 بأنه في حالة حدوث استثناء من النوع [RdvMedecinsException] داخل طريقة يتم تنفيذها ضمن معاملة تحتوي على SGBD، فيجب إلغاء هذه المعاملة. من الناحية الفنية، يُطلق على ذلك اسم «إجراء rollback» للمعاملة.
4.6.4. Ejb الخاص بطبقة [dao]
![]() |
![]() |
واجهة Java [IDao] للطبقة [dao] هي كما يلي:
تكتفي الواجهة المحلية [IDaoLocal] لـ Ejb باشتقاق الواجهة السابقة [IDao]:
وينطبق الأمر نفسه على الواجهة البعيدة [IDaoRemote]:
تقوم EJB [DaoJpa] بتنفيذ كلتا الواجهتين، المحلية والبعيدة:
- تشير السطر 3 إلى أن EJB البعيد يحمل الاسم "rdvmedecins.dao"
- تشير السطر 4 إلى أن جميع أساليب EJB تتم ضمن معاملة يديرها حاوية EJB3.
- يُظهر السطر 5 أن EJB يُنفذ الواجهتين المحلية والبعيدة.
فيما يلي الكود الكامل لـ EJB:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | |
- السطر 8: الكائن EntityManager الذي يدير الوصول إلى سياق الاستمرارية. عند إنشاء مثيل للفئة، سيتم تهيئة هذا الحقل بواسطة حاوية EJB بفضل التعليق التوضيحي @PersistenceContext في السطر 7.
- السطر 15: استعلام JPQL الذي يُرجع جميع السجلات من الجدول [clients] في شكل قائمة من الكائنات [Client].
- السطر 22: استعلام مماثل للأطباء
- السطر 32: استعلام JPQL يقوم بدمج الجدولين [creneaux] و [medecins]. ويتم تعيين معلماته باستخدام معرّف الطبيب.
- السطر 43: استعلام JPQL يقوم بدمج الجداول [rv] و [creneaux] و [medecins]، وله معلمتان: معرّف الطبيب ويوم الموعد.
- الأسطر 55-57: إنشاء موعد طبي ثم حفظه في قاعدة البيانات.
- السطر 67: حذف موعد من قاعدة البيانات.
- السطر 76: تنفيذ عملية استعلام (SELECT) في قاعدة البيانات للعثور على عميل معين
- السطر 85: الأمر نفسه بالنسبة للطبيب
- السطر 94: الأمر نفسه بالنسبة لموعد
- السطر 103: الأمر نفسه بالنسبة لفترة زمنية
- جميع العمليات التي تستخدم سياق الاستمرارية em الوارد في السطر 9 قد تواجه مشكلة مع قاعدة البيانات. ولذلك، فإنها جميعًا محاطة بعبارة try / catch. يتم تغليف الاستثناء المحتمل في الاستثناء "الداخلي" RdvMedecinsException.
بعد ترجمة الوحدة النمطية Ejb، يتم إنشاء ملف .jar باسم :
![]() |
4.7. نشر وحدة EJB الخاصة بطبقة [dao] باستخدام NetBeans
يتيح NetBeans نشر مكون EJB الذي تم إنشاؤه مسبقًا على خادم GlassFish بطريقة بسيطة.
![]() |
- في خصائص مشروع EJB، تحقق من خيارات التشغيل [1].
- في [2]، اسم الخادم الذي سيتم نشر تطبيق EJB عليه
- في علامة التبويب [Services] [3]، يتم تشغيله [4].
![]() |
- في [5]، خادم Glassfish بمجرد تشغيله. لا يحتوي بعد على وحدة EJB.
- قم بتشغيل الخادم MySQL وتأكد من أن قاعدة البيانات [dbrdvmedecins] متصلة بالشبكة. للقيام بذلك، يمكنك استخدام اتصال NetBeans الذي تم إنشاؤه في الفقرة 4.5.
- في علامة التبويب [Projects] [6]، يتم نشر وحدة EJB [7]: يجب تشغيل SGBD MySQL5 حتى يصبح المورد JDBC "jdbc/dbrdvmedecins" الذي تستخدمه وحدة EJB متاحًا.
- في [8]، يظهر EJB الذي تم نشره في شجرة الخادم Glassfish
![]() |
- في [9]، يتم إزالة تطبيق EJB الذي تم نشره
- في [10]، لم يعد EJB يظهر في شجرة الخادم Glassfish.
4.8. نشر EJB الخاص بالطبقة [dao] باستخدام Glassfish
نوضح هنا كيفية نشر EJB على خادم Glassfish من ملف .jar الخاص به.
- قم بتشغيل الخادم MySQL وتأكد من أن قاعدة البيانات [dbrdvmedecins] متصلة بالإنترنت. وللقيام بذلك، يمكنك استخدام اتصال NetBeans الذي تم إنشاؤه في الفقرة 4.5.
دعونا نستعرض تكوين JPA للوحدة EJB التي سيتم نشرها. يتم إجراء هذا التكوين في الملف [persistence.xml]:
تشير السطر 5 إلى أن طبقة Jpa تستخدم مصدر بيانات JTA، c.a.d، الذي يديره الحاوية Ejb3، والمسمى "jdbc/dbrdvmedecins".
لقد رأينا في الفقرة 4.5 كيفية إنشاء هذا المورد JDBC من خلال NetBeans. ونوضح هنا كيفية القيام بذلك مباشرةً باستخدام GlassFish. ونتبع هنا الإجراء الموصوف في الفقرة 13.1.2، الصفحة 79 من [ref1].
نبدأ بحذف المورد حتى نتمكن من إعادة إنشائه. نقوم بذلك من خلال NetBeans:
![]() |
- في [1]، الموارد JDBC الخاصة بخادم Glassfish
- إلى [2]، والمورد "jdbc/dbrdvmedecins" الخاص بـ Ejb الخاص بنا
- إلى [3]، ومجموعة اتصالات هذا المورد JDBC
![]() |
- في [4]، نقوم بحذف مجموعة الاتصالات. سيؤدي ذلك إلى حذف جميع الموارد JDBC التي تستخدمها، وبالتالي المورد "jdbc/dbrdvmedecins".
- في [5] و [6]، تم إزالة المورد JDBC ومجموعة الاتصالات.
الآن، نستخدم وحدة التحكم الإدارية لخادم Glassfish لإنشاء المورد JDBC ونشر EJB.
![]() |
- في علامة التبويب [services] [1] في NetBeans، قم بتشغيل خادم Glassfish [2] ثم قم بالوصول إلى [3] لوحدة التحكم الإدارية الخاصة به
- في [4]، وقم بتسجيل الدخول كمسؤول (كلمة المرور: adminadmin إذا لم تكن قد قمت بتغييرها أثناء التثبيت أو بعده).
![]() |
- إلى [5]، حدد الفرع [Connection Pools] من موارد Glassfish
- في [6]، قم بإنشاء تجمع اتصالات جديد. تجدر الإشارة إلى أن تجمع الاتصالات هو تقنية تهدف إلى الحد من عدد مرات فتح/إغلاق الاتصالات مع SGBD. عند بدء تشغيل الخادم، يتم فتح عدد N من الاتصالات مع SGBD، حيث يتم تحديد هذا العدد من خلال التكوين. ثم يتم إتاحة هذه الاتصالات المفتوحة لـ EJB التي تطلبها لإجراء عملية مع SGBD. بمجرد انتهاء العملية، تعيد مكونة EJB الاتصال إلى المجمع. لا يتم إغلاق الاتصال أبدًا. بل يتم مشاركته بين الخيوط المختلفة التي تصل إلى SGBD
- في [7]، قم بتسمية المجمع
- في [8]، والفئة التي تمثل مصدر البيانات هي الفئة [javax.sql.DataSource]
- في [9]، و SGBD الذي يحتوي على مصدر البيانات هو هنا MySQl.
- في [10]، انتقل إلى الخطوة التالية
![]() |
- في [11]، يؤدي السمة "Connection Validation Required" إلى أن يقوم المجمع، قبل منح اتصال، بالتحقق من أنه يعمل. إذا لم يكن الأمر كذلك، فإنه ينشئ اتصالاً جديداً. وهذا يسمح للتطبيق بمواصلة العمل بعد انقطاع مؤقت في الاتصال بـ SGBD. أثناء الانقطاع، لا يكون أي اتصال قابلاً للاستخدام ويتم إرسال استثناءات إلى العميل. وعند انتهاء الانقطاع، يحصل العملاء الذين يواصلون طلب الاتصالات عليها مرة أخرى: بفضل السمة "Connection Validation Required"، سيتم إعادة إنشاء جميع اتصالات المجمع. وبدون هذه السمة، سيلاحظ المجمع أن الاتصالات الأولية قد انقطعت ولكنه لن يسعى إلى إنشاء اتصالات جديدة.
- في [12]، يُطلب مستوى العزل «Read Committed» للمعاملات. يضمن هذا المستوى أن المعاملة T2 لا يمكنها قراءة البيانات التي تم تعديلها بواسطة المعاملة T1 ما لم تكن هذه الأخيرة قد اكتملت تمامًا.
- في [13]، يُطلب أن تستخدم جميع المعاملات مستوى العزل المحدد في [12]
![]() |
- في [14] و [15]، حدد عنوان URL الخاص بـ BD الذي يدير مجمعه الاتصالات
- في [16]، سيكون المستخدم هو root
- في [17]، أضف خاصية
- في [18]، أضف الخاصية "Password" بالقيمة () في [19]. على الرغم من أن لقطة الشاشة [19] لا تظهر ذلك، يجب عدم إدخال سلسلة فارغة بل () (قوس مفتوح، قوس مغلق) للإشارة إلى كلمة مرور فارغة. إذا كان المستخدم root في قاعدة البيانات SGBD MySQL لديه كلمة مرور غير فارغة، فقم بإدخال كلمة المرور هذه.
- في [20]، أكمل مساعد إنشاء مجموعة الاتصالات لقاعدة البيانات MySQL [dbrdvmedecins].
![]() |
- في [21]، تم إنشاء مجموعة الاتصالات. انقر على الرابط الخاص بها.
- في [22]، يتيح الزر [Ping] إنشاء اتصال بقاعدة البيانات [dbrdvmedecins]
- في [23]، إذا سارت الأمور على ما يرام، ستظهر رسالة تفيد بنجاح الاتصال
بمجرد إنشاء مجموعة الاتصالات، يمكن إنشاء مورد Jdbc:
![]() |
- في [1]، نختار الفرع [JDBC Resources] من شجرة كائنات الخادم
- في [2]، نقوم بإنشاء مورد جديد JDBC
- في [3]، نسمي المورد JDBC. يجب أن يتطابق هذا الاسم مع الاسم المستخدم في الملف [persistence.xml]:
- في [4]، نحدد مجموعة الاتصالات التي يجب أن تستخدمها المورد الجديد JDBC: وهي المجموعة التي أنشأناها للتو
- في ملف [5]، ننهي مساعد الإنشاء
![]() |
- في [6] المورد الجديد JDBC
الآن بعد إنشاء المورد JDBC، يمكننا نشر ملف jar الخاص بـ Ejb:
![]() |
- إلى [1]، حدد الفرع [Enterprise Applications]
- إلى [2]، باستخدام الزر [Deploy]، حدد أنك تريد نشر تطبيق جديد
- في [3]، حدد أن التطبيق هو وحدة EJB
- في [4]، حدد ملف jar الخاص بـ Ejb [serveur-ejb-dao-jpa-hibernate.jar] الذي تم تزويدك به من أجل TP.
- في [5]، يمكنك تغيير اسم وحدة EJB إذا رغبت في ذلك
- في [6]، أكمل مساعد نشر وحدة ejb
![]() |
- في [7]، تم نشر الوحدة النمطية Ejb. ويمكن الآن استخدامها.
4.9. اختبارات وحدة Ejb الخاصة بطبقة [dao]
الآن بعد أن تم نشر وحدة Ejb الخاصة بطبقة [dao] في تطبيقنا، يمكننا اختبارها. سنقوم بذلك باستخدام عميل Java التالي:
![]() |
الفئة [MainTestsDaoRemote] [1] هي فئة اختبار JUnit 4. تتكون المكتبات في [2] من جانب:
- ملف jar الخاص بـ EJB في الطبقة [dao] [3] (انظر الفقرة 4.6.4).
- مكتبات Glassfish [4] اللازمة للعملاء البعيدين لـ Ejb.
فئة الاختبار هي التالية:
- السطر 13: لاحظ إنشاء مثيل للوكيل الخاص بـ EJB البعيد. نستخدم اسمه JNDI "rdvmedecins.dao".
- تستخدم طرق الاختبار الطرق التي يعرضها EJB (انظر الفقرة 4.6.4).
إذا سارت الأمور على ما يرام، يجب أن تنجح الاختبارات:
![]() |
الآن بعد أن أصبح EJB الخاص بالطبقة [dao] جاهزًا للعمل، يمكننا الانتقال إلى عرضه للجمهور عبر خدمة ويب.
4.10. خدمة الويب الخاصة بالطبقة [dao]
للحصول على مقدمة موجزة لمفهوم خدمة الويب، يمكن الرجوع إلى الفقرة 14، الصفحة 111 من [ref1].
لنعد إلى بنية خادم تطبيقنا العميل/الخادم:
![]() |
نحن نهتم هنا بخدمة الويب الخاصة بالطبقة [dao]. وتتمثل المهمة الوحيدة لهذه الخدمة في إتاحة واجهة EJB الخاصة بالطبقة [dao] للعملاء متعددي المنصات القادرين على التفاعل مع خدمة ويب.
تجدر الإشارة إلى أن هناك طريقتين لتنفيذ خدمة ويب:
- عن طريق فئة مُعلَّمة بـ @WebService تُنفَّذ في حاوية ويب
![]() |
- عن طريق كائن EJB مُعلَّم بـ @WebService والذي يتم تنفيذه في حاوية EJB
![]() |
نستخدم هنا الحل الأول. في NetBeans IDE، يتعين علينا إنشاء مشروع مؤسسي يتألف من وحدتين:
- وحدة EJB التي ستُنفَّذ في حاوية EJB: EJB الخاصة بطبقة [dao].
- وحدة الويب التي ستُنفَّذ في حاوية الويب: خدمة الويب التي نقوم بإنشائها حاليًا.
سنقوم بإنشاء هذا المشروع المؤسسي بطريقتين.
4.10.1. مشروع NetBeans - الإصدار 1
نبدأ أولاً بإنشاء مشروع NetBeans من نوع «Web Application»:
![]() |
- في [1]، نقوم بإنشاء مشروع جديد ضمن فئة «Java Web» [2] من نوع «Web Application» [3].
![]() |
- في [4]، نسمي المشروع، وفي [5] نحدد المجلد الذي سيتم إنشاؤه فيه
- في [6]، يتم تحديد خادم التطبيق الذي سيقوم بتنفيذ تطبيق الويب
- في [7]، يتم تحديد سياق التطبيق
- في [8]، يتم التحقق من صحة تكوين المشروع.
![]() |
- في [9]، يتم إنشاء المشروع. ستستخدم خدمة الويب التي نقوم بإنشائها ملف EJB من المشروع السابق [10]. ولذلك، فإنها تحتاج إلى الإشارة إلى ملف .jar الخاص بوحدة Ejb [10].
- في [11]، نضيف مشروع NetBeans إلى مكتبات مشروع الويب [12]
![]() |
- في [13]، نختار مجلد وحدة Ejb في نظام الملفات ونؤكد الاختيار.
![]() |
- في [14]، تمت إضافة الوحدة النمطية Ejb إلى مكتبات مشروع الويب.
في [15]، نقوم بتنفيذ خدمة الويب باستخدام الفئة [WsDaoJpa] التالية:
- في السطر 4، تقوم الفئة [WsdaoJpa] بتنفيذ الواجهة [IDao]. تجدر الإشارة إلى أن هذه الواجهة محددة في أرشيف EJB للطبقة [dao] بالشكل التالي:
- السطر 3: التعليق التوضيحي @WebService يجعل من الفئة [WsDaoJpa] خدمة ويب.
- السطران 6-7: سيتم إدخال مرجع EJB الخاص بالطبقة [dao] بواسطة خادم التطبيق في حقل السطر 7. تجدر الإشارة إلى أن التنفيذ المحلي (IDaoLocal في هذه الحالة) هو الذي يتم حقنه دائمًا. ويكون هذا الحقن ممكنًا لأن خدمة الويب تُنفَّذ في نفس JVM التي يعمل فيها EJB.
- يتم تمييز جميع أساليب خدمة الويب بعلامة التعليق التوضيحي @WebMethod لجعلها أساليب مرئية للعملاء البعيدين. أما الأسلوب غير المميز بعلامة التعليق التوضيحي @WebMethod فسيكون داخليًّا في خدمة الويب وغير مرئي للعملاء البعيدين. تكتفي كل طريقة M في خدمة الويب باستدعاء الطريقة M المقابلة في EJB الذي تم حقنه في السطر 7.
ينعكس إنشاء خدمة الويب هذه في فرع جديد في مشروع NetBeans:
![]() |
نرى في [1] خدمة الويب WsDaoJpa، وفي [2] الطرق التي تعرضها للعملاء البعيدين.
دعونا نستعرض بنية خدمة الويب قيد الإنشاء:
![]() |
مكونات خدمة الويب التي سنقوم بنشرها هي:
- [1]: الوحدة النمطية للويب التي أنشأناها للتو
- [2]: وحدة EJB التي أنشأناها في خطوة سابقة والتي تعتمد عليها خدمة الويب
لنشرهما معًا، يجب تجميع الوحدتين في مشروع NetBeans يُعرف باسم «مشروع مؤسسي»:
![]() |
في [1]، نقوم بإنشاء مشروع مؤسسي جديد باسم [2, 3].
![]() |
- في [4,5]، نسمي المشروع ونحدد مجلد إنشائه
- في [6]، يتم اختيار خادم التطبيق الذي سيتم نشر تطبيق المؤسسة عليه
- في [7]، يمكن أن يتكون مشروع المؤسسة من ثلاثة مكونات: تطبيق ويب، وحدة EJB، وتطبيق عميل. هنا، يتم إنشاء المشروع بدون أي مكونات. وسيتم إضافة هذه المكونات لاحقًا.
![]() |
- في [8]، تطبيق المؤسسة الذي تم إنشاؤه حديثًا.
![]() |
- في [9]، انقر بزر الماوس الأيمن على [Java EE Modules] وأضف وحدة جديدة
- في [10]، لا تظهر سوى وحدات NetBeans المفتوحة حاليًا في IDE. هنا نختار وحدة الويب [serveur-webservice-1-ejb-dao-jpa-hibernate] ووحدة EJB [serveur-ejb-dao-jpa-hibernate] اللتين قمنا بإنشائهما.
- في [11]، تظهر الوحدتان اللتان تمت إضافتهما إلى مشروع المؤسسة.
يبقى لنا الآن نشر هذا التطبيق المؤسسي على خادم Glassfish. في الخطوة التالية، يجب تشغيل SGBD و MySQL حتى يصبح مصدر البيانات JDBC «jdbc/dbrdvmedecins» الذي تستخدمه الوحدة النمطية Ejb متاحًا.
![]() |
- في [1]، يتم تشغيل خادم Glassfish
- إذا تم نشر الوحدة النمطية Ejb [serveur-ejb-dao-jpa-hibernate]، يتم إيقاف تشغيلها [2]
- إلى [3]، يتم نشر تطبيق المؤسسة
![]() |
- في [4]، يتم نشره. نلاحظ أنه يحتوي على الوحدتين: Web و Ejb.
4.10.2. مشروع NetBeans - الإصدار 2
نوضح الآن كيفية نشر خدمة الويب عندما لا يتوفر لدينا كود المصدر للوحدة النمطية Ejb بل يتوفر فقط ملفها المضغوط .jar.
سيكون مشروع NetBeans الجديد لخدمة الويب كما يلي:
![]() |
العناصر البارزة في المشروع هي التالية:
- [1]: يتم تنفيذ خدمة الويب من خلال مشروع NetBeans من النوع [Web Application].
- [2]: يتم تنفيذ خدمة الويب بواسطة الفئة [WsDaoJpa] التي تمت دراستها سابقًا
- [3]: أرشيف EJB للطبقة [dao] الذي يتيح للفئة [WsDaoJpa] الوصول إلى تعريفات الفئات والواجهات والكيانات المختلفة في الطبقتين [dao] و [jpa].
ثم نقوم بإنشاء مشروع المؤسسة اللازم لنشر خدمة الويب:
![]() |
- [1]، وننشئ تطبيقًا مؤسسيًا [ea-rdvmedecins]، في البداية بدون أي وحدة نمطية.
- في [2]، نضيف الوحدة النمطية الويب السابقة [serveur-webservice-ejb-dao-jpa-hibernate]
- في [3]، النتيجة.
بصيغتها الحالية، لا يمكن نشر تطبيق المؤسسة [ea-rdvmedecins] على خادم Glassfish من NetBeans. تظهر رسالة خطأ. لذا، يجب نشر ملف الأرشيف ear الخاص بالتطبيق [ea-rdvmedecins] يدويًّا:
![]() |
- يوجد الأرشيف [ea-rdvmedecins.ear] في المجلد [dist] [2] ضمن علامة التبويب [Files] في NetBeans.
- في هذا الأرشيف [3]، نجد عنصري التطبيق المؤسسي التاليين:
- أرشيف EJB [serveur-ejb-dao-jpa-hibernate]. يوجد هذا الأرشيف لأنه كان جزءًا من المكتبات المشار إليها بواسطة خدمة الويب.
- أرشيف خدمة الويب [serveur-webservice- ejb-dao-jpa-hibernate].
- تم إنشاء الأرشيف [ea-rdvmedecins.ear] من خلال أرشيفين بسيطين Build و [4] من تطبيق المؤسسة.
- في [5]، عملية النشر التي تفشل.
لنشر ملف الأرشيف [ea-rdvmedecins.ear] الخاص بتطبيق المؤسسة، نتبع نفس الإجراءات التي تم توضيحها عند نشر ملف أرشيف EJB [serveur-ejb-dao-jpa-hibernate.jar] في الفقرة 4.2. ونستخدم مرة أخرى عميل الويب الخاص بإدارة خادم Glassfish. لن نكرر الخطوات التي سبق وصفها.
أولاً، سنبدأ بـ«إلغاء نشر» التطبيق المؤسسي الذي تم نشره في الفقرة 4.10.1:
![]() |
- [1]: حدد الفرع [Enterprise Applications] لخادم Glassfish
- في [2]، حدد التطبيق المؤسسي المراد إلغاء تحميله، ثم في [3]، قم بإلغاء تحميله
- في [4] تم تفريغ تطبيق المؤسسة
![]() |
- في [1]، اختر الفرع [Enterprise Applications] لخادم Glassfish
- في [2]، قم بنشر تطبيق مؤسسي جديد
- في [3]، حدد النوع [Enterprise Application]
- في [4]، حدد ملف .ear الخاص بمشروع NetBeans [ea-rdvmedecins]
- في [5]، قم بنشر هذا الأرشيف
![]() |
- إلى [6]، تم نشر التطبيق
- في [7]، تظهر خدمة الويب [WsDaoJpa] في الفرع [Web Services] لخادم Glassfish. قم بتحديدها.
- في [8]، تتوفر معلومات متنوعة عن خدمة الويب. وأهمها بالنسبة للعميل هي المعلومات الموجودة في [9]: عنوان URI لخدمة الويب.
- في [10]، يمكن اختبار خدمة الويب
![]() |
- في [11]، نجد عنوان URI لخدمة الويب الذي أُضيفت إليه المعلمة ?tester. يعرض عنوان URI هذا صفحة اختبار. يتم عرض جميع الطرق (@WebMethod) التي توفرها خدمة الويب ويمكن اختبارها. هنا، يتم اختبار الطريقة [13] التي تطلب قائمة العملاء.
![]() |
- في [14]، لا نعرض سوى جزء من صفحة الرد. لكن يمكننا أن نرى أن الطريقة getAllClients قد أرجعت بالفعل قائمة العملاء. تُظهر لنا لقطة الشاشة أنها ترسل استجابتها بتنسيق XML.
يتم وصف خدمة الويب بالكامل بواسطة ملف يُسمى XML:
![]() |
- في ملف [1] في أداة إدارة الويب الخاصة بخادم Glassfish، حدد خدمة الويب [WsDaoJpa]
- إلى [2]، ثم اتبع الرابط [View WSDL]
![]() |
- إلى [3]: عنوان URI لملف WSDL. هذه معلومة مهمة يجب معرفتها. فهي ضرورية لتكوين عملاء خدمة الويب هذه.
- في [4]، الوصف XML لخدمة الويب. لن نعلق على هذا المحتوى المعقد.
4.10.3. اختبارات الخدمة الويب JUnit
نقوم بإنشاء مشروع NetBeans لـ«تشغيل» الاختبارات التي تم إجراؤها مسبقًا باستخدام عميل EJB، ولكن هذه المرة باستخدام عميل لخدمة الويب التي تم نشرها مؤخرًا. ونتبع هنا نهجًا مشابهًا للنهج الموصوف في الفقرة 14.2.1، الصفحة 115 من [ref1].
![]() |
- في [1]، مشروع Java تقليدي
- في [2]، فئة الاختبار
- في [3]، يستخدم العميل أرشيف EJB للوصول إلى تعريفات واجهة الطبقة [dao] وكيانات JPA. تجدر الإشارة إلى أن هذا الأرشيف موجود في المجلد الفرعي [dist] التابع لمجلد وحدة EJB.
للوصول إلى خدمة الويب البعيدة، من الضروري إنشاء فئات بروكسي:
![]() |
في المخطط أعلاه، تتواصل الطبقة [2] [C=Client] مع الطبقة [1] [S=Serveur]. للتواصل مع الطبقة [S]، يتعين على العميل [C] إنشاء اتصال شبكي مع الطبقة [S] والتواصل معها وفقًا لبروتوكول محدد. اتصالات الشبكة هي اتصالات TCP وبروتوكول النقل هو HTTP. يتم تنفيذ الطبقة [S] التي تمثل خدمة الويب بواسطة سيرفلت جافا يتم تشغيله بواسطة خادم Glassfish. لم نقم بكتابة هذه الخدمة. يتم إنشاؤها تلقائيًا بواسطة Glassfish استنادًا إلى التعليقات التوضيحية @Webservice و@WebMethod في الفئة [WsDaoJpa] التي قمنا بكتابتها. وبالمثل، سنقوم بأتمتة إنشاء الطبقة [C] الخاصة بالعميل. يُطلق أحيانًا على الطبقة [C] اسم «طبقة الوكيل» لخدمة الويب البعيدة، حيث يشير مصطلح proxy إلى عنصر وسيط في سلسلة برمجية. هنا، يُعد الوكيل C الوسيط بين العميل الذي سنقوم بكتابته وخدمة الويب التي قمنا بنشرها.
باستخدام NetBeans 6.5، يمكن إنشاء الوكيل C بالطريقة التالية (للمتابعة، يجب أن تكون خدمة الويب نشطة على خادم Glassfish):
![]() |
- في [1]، أضف عنصرًا جديدًا إلى مشروع Java
- في [2]، حدد الفرع [Web services]
- في [3]، حدد [Web Service Client]
![]() |
- في [4]، أدخل عنوان URI لملف WSDL الخاص بخدمة الويب. وقد تم عرض عنوان URI هذا في الفقرة 4.10.2.
- في [5]، اترك القيمة الافتراضية [JAX-WS]. القيمة الأخرى الممكنة هي [JAX-RPC]
- بعد إتمام معالج إنشاء الوكيل لخدمة الويب، تمت إضافة فرع [Web Service References] [6] إلى مشروع NetBeans. يُظهر هذا الفرع الطرق التي توفرها خدمة الويب البعيدة.
![]() |
- في علامة التبويب [Files] [7]، تمت إضافة أكواد مصدرية بلغة Java [8]. وهي تتوافق مع الوكيل C الذي تم إنشاؤه.
- في [9] نجد كود إحدى الفئات. ونلاحظ في [10] أنها وُضعت في حزمة [rdvmedecins.ws]. ولن نعلق على كود هذه الفئات الذي يتسم مرة أخرى بالتعقيد.
بالنسبة لعميل Java الذي نقوم ببنائه حاليًا، يعمل الوكيل C الذي تم إنشاؤه كوسيط. للوصول إلى الطريقة M لخدمة الويب البعيدة، يستدعي عميل Java الطريقة M للوكيل C. وبذلك، يستدعي عميل Java طرقًا محلية (يتم تنفيذها في نفس JVM)، وبطريقة شفافة بالنسبة له، يتم ترجمة هذه الاستدعاءات المحلية إلى استدعاءات بعيدة.
يبقى علينا معرفة كيفية استدعاء الطرق M للوكيل C. لنعد إلى فئة الاختبار JUnit:
![]() |
في [1]، فئة الاختبار [MainTestsDaoRemote] هي نفسها التي تم استخدامها سابقًا عند اختبار EJB الخاص بالطبقة [dao]:
- في السطر [13]، تم الاحتفاظ باختبار test1 دون تغيير.
- السطر [9]، تم حذف محتوى الطريقة [init].
في هذه المرحلة، يحتوي المشروع على أخطاء لأن طريقة الاختبار [test1] تستخدم الكيانات [Client] و[Medecin] و[Creneau]، [Rv] التي لم تعد موجودة في الحزم نفسها كما في السابق. فهي موجودة الآن في حزمة الوكيل C الذي تم إنشاؤه. يتم حذف التعليمات import المعنية وإعادة إنشائها من خلال عملية «Fix Imports».
![]() |
لنعد إلى كود فئة الاختبار [MainTestsDaoRemote]:
يجب أن تقوم الطريقة [init] في السطر 10 بتهيئة مرجع الطبقة [dao] في السطر 7. نحتاج إلى معرفة كيفية استخدام الوكيل C الذي تم إنشاؤه في كودنا. يساعدنا NetBeans في هذه الخطوة.
![]() |
- حدد في [1] الطريقة [getAllClients] الخاصة بخدمة الويب، ثم اسحب هذه الطريقة بالماوس وأسقطها داخل الطريقة [init] في فئة الاختبار.
ونحصل على النتيجة [2]. يوضح لنا هذا الهيكل الأساسي للكود كيفية استخدام الوكيل C الذي تم إنشاؤه:
- يُظهر لنا السطر [5] أن الطريقة [getAllClients] هي طريقة للكائن من النوع [WsDaoJpa] المُعرَّف في السطر 3. النوع [WsDaoJpa] هو واجهة تحتوي على نفس الطرق التي يعرضها خدمة الويب البعيدة.
- في السطر [3]، يتم الحصول على الكائن [WsDaoJpa port] من كائن آخر من النوع [WsDaoJpaService] المُعرَّف في السطر 2. يمثل النوع [WsDaoJpaService] الوكيل C الذي تم إنشاؤه محليًّا.
- قد يفشل الوصول إلى خدمة الويب البعيدة، ولذلك تم تضمين الكود بأكمله في جملة try / catch.
- توجد كائنات الوكيل C في الحزمة [rdvmedecins.ws]
بمجرد فهم هذا الكود، يتضح أن المرجع المحلي لخدمة الويب البعيدة يمكن الحصول عليه من خلال الكود التالي:
وبذلك يصبح كود فئة الاختبار JUnit كما يلي:
نحن الآن جاهزون لإجراء الاختبارات:
![]() |
في [1]، يتم تنفيذ الاختبار JUnit. وفي [2]، يتم اجتيازه بنجاح. إذا نظرنا إلى العروض على وحدة التحكم Netbeans، نجد أسطرًا مثل التالية:
Liste des clients :
rdvmedecins.ws.Client@1982fc1
rdvmedecins.ws.Client@676437
rdvmedecins.ws.Client@1e4853f
rdvmedecins.ws.Client@1e808ca
على جانب الخادم، تحتوي الكيان [Client] على طريقة toString التي تعرض الحقول المختلفة لكائن من النوع [Client]. أثناء الإنشاء التلقائي للوكيل C، يتم إنشاء الكيانات في الوكيل C ولكن مع الحقول الخاصة فقط مصحوبة بأساليب get / set الخاصة بها. وبالتالي، لم يتم إنشاء الأسلوب toString في الكيان [Client] التابع للوكيل C. وهذا ما يفسر العرض السابق. ولا يؤثر ذلك على اختبار JUnit: فقد تم اجتيازه بنجاح. وسنعتبر من الآن فصاعدًا أن لدينا خدمة ويب جاهزة للعمل.






























































































