Skip to content

6. عملاء Flex لخدمة المواعيد JEE

نقدم الآن عميلين Flex لخدمة الويب JEE الخاصة بالمواعيد. يتم استخدام Flex Builder 3. يمكن تنزيل نسخة تجريبية من هذا المنتج من الرابط [https://www.adobe.com/cfusion/tdrc/index.cfm?loc=fr_fr&product=flex]. يُعد Flex Builder 3 أحد مكونات Eclipse. علاوة على ذلك، لتشغيل عميل Flex، نستخدم خادم ويب Apache من أداة Wamp. يمكن استخدام أي خادم Apache آخر. يجب أن يكون المتصفح الذي يعرض عميل Flex مزودًا بمكوّن Flash Player الإضافي، الإصدار 9 كحد أدنى.

تتميز تطبيقات Flex بأنها تعمل داخل المكون الإضافي Flash Player في المتصفح. وفي هذا الشأن، فهي تشبه تطبيقات Ajax التي تضم نصوصًا برمجية JavaScript في الصفحات المرسلة إلى المتصفح، والتي يتم تنفيذها لاحقًا داخل المتصفح. تطبيق Flex ليس تطبيقًا ويب بالمعنى المعتاد للكلمة: إنه تطبيق عميل لخدمات تقدمها خوادم الويب. وفي هذا الصدد، فهو مشابه لتطبيق سطح المكتب الذي يكون عميلاً لهذه الخدمات نفسها. لكنه يختلف في نقطة واحدة: يتم تنزيله مبدئيًا من خادم ويب داخل متصفح مزود بمكوّن Flash Player الإضافي القادر على تشغيله.

مثل أي تطبيق مكتبي، يتكون تطبيق Flex بشكل أساسي من عنصرين:

  • جزء العرض: العروض المعروضة في المتصفح. تتمتع هذه العروض بنفس ثراء نوافذ تطبيقات سطح المكتب. يتم وصف العرض باستخدام لغة علامات تُسمى MXML.
  • جزء الكود الذي يدير بشكل أساسي الأحداث الناتجة عن إجراءات المستخدم على العرض. يمكن كتابة هذا الكود أيضًا بلغة MXML أو بلغة موجهة للكائنات تُسمى ActionScript. يجب التمييز بين نوعين من الأحداث:
  • الحدث الذي يتطلب إجراء تبادل مع خادم الويب: ملء قائمة بالبيانات المقدمة من تطبيق ويب، وإرسال بيانات نموذج إلى الخادم، ... يوفر Flex عددًا من الطرق للتواصل مع الخادم بطريقة شفافة بالنسبة للمطور. هذه الطرق غير متزامنة بشكل افتراضي: يمكن للمستخدم الاستمرار في التفاعل مع العرض أثناء إرسال الطلب إلى الخادم.
  • الحدث الذي يغير العرض المرئي دون تبادل البيانات مع الخادم، على سبيل المثال سحب عنصر من شجرة لإفلاته في قائمة. يتم معالجة هذا النوع من الأحداث بالكامل محليًّا داخل المتصفح.

غالبًا ما يتم تشغيل تطبيق Flex بالطريقة التالية:

  • في [1]، يتم طلب صفحة HTML
  • في [2]، يتم إرسالها. وهي تحمل معها ملفًا ثنائيًا SWF (ShockWave Flash) يحتوي على التطبيق Flex بالكامل: جميع العروض ورمز إدارة الأحداث الخاصة بها. سيتم تنفيذ هذا الملف بواسطة المكون الإضافي FlashPlayer في المتصفح.
  • يتم تشغيل عميل Flex محليًا على المتصفح إلا عندما يحتاج إلى بيانات خارجية. في هذه الحالة، يطلبها من الخادم [3]. ويستلمها في [4] وفقًا لتنسيقات متنوعة: XML أو ثنائي. يمكن كتابة التطبيق الذي يتم الاستعلام عنه على خادم الويب بأي لغة برمجة. ما يهم هو تنسيق الرد فقط.

لقد وصفنا بنية تشغيل تطبيق Flex حتى يدرك القارئ جيدًا الفرق بينها وبين بنية تطبيق ويب تقليدي، بدون Ajax، مثل التطبيق Asp.Net الموصوف سابقًا. في هذا الأخير، يكون المتصفح سلبيًّا: فهو يعرض ببساطة صفحات HTML التي تم إنشاؤها على خادم الويب الذي يرسلها إليه.

في ما يلي، نقدم مثالين على عملاء Flex بهدف وحيد هو إظهار تنوع عملاء خدمة الويب. ونظرًا لأن المؤلف نفسه مبتدئ في استخدام Flex، فقد لا يتم تفصيل بعض النقاط بالشكل المطلوب.

6.1. عميل Flex الأول

سنقوم الآن بكتابة عميل Flex الأول لعرض قائمة العملاء. وستكون بنية العميل/الخادم التي سيتم تنفيذها كما يلي:

في هذه البنية، يوجد خادمان ويب:

  • خادم Glassfish الذي يقوم بتشغيل خدمة الويب البعيدة
  • خادم Apache الذي يقوم بتشغيل عميل Flex الخاص بخدمة الويب البعيدة

نقوم بإنشاء عميل Flex باستخدام IDE Flex Builder 3:

  • في Flex Builder 3، نقوم بإنشاء مشروع جديد في [1]
  • ونسميه [2] ونحدد في [3] المجلد الذي سيتم إنشاؤه فيه
  • في [4]، نسمي التطبيق الرئيسي (الذي سيتم تنفيذه)
  • في [5]، يتم إنشاء المشروع
  • في [6]، الملف الرئيسي للتطبيق MXML
  • يحتوي الملف MXML على عرض ورمز إدارة أحداث هذا العرض. تتيح علامة التبويب [Source] [7] الوصول إلى الملف MXML. وستجد فيه علامات <mx> تصف العرض بالإضافة إلى كود ActionScript.
  • يمكن إنشاء العرض بيانيًّا باستخدام علامتي التبويب [Design] و[8]. وعندئذٍ يتم إنشاء علامات MXML التي تصف العرض تلقائيًّا في علامة التبويب [Source]. والعكس صحيح أيضًا: العلامات MXML التي تمت إضافتها مباشرةً في علامة التبويب [Source] تنعكس بيانيًّا في علامة التبويب [Design].

وكما حدث مع عملاء C# وAsp.Net السابقين، سنقوم بإنشاء الوكيل المحلي C [B] لخدمة الويب البعيدة S [A]:

لكي يتم إنشاء الوكيل C، يجب أن تكون خدمة الويب JEE نشطة.

  • في [1]، اختر الخيار «Data / Import Web Service»
  • في [2]، حدد المجلد الخاص بإنشاء فئات وواجهات الوكيل C.
  • في [3]، أدخل عنوان URI لملف WSDL الخاص بخدمة الويب البعيدة S (انظر الفقرة 4.10.2) ثم انتقل إلى الخطوة التالية
  • في [4] و [5]، يتم وصف خدمة الويب بواسطة الملف WSDL المشار إليه في [3]
  • في [6]: قائمة الطرق التي سيتم إنشاؤها للوكيل C. تجدر الإشارة إلى أن هذه ليست الطرق الفعلية لخدمة S. فهي لا تحمل التوقيع الصحيح. هنا، تحتوي كل طريقة معروضة على معلمة واحدة بغض النظر عن عدد معلمات الطريقة الفعلية لخدمة الويب. هذه المعلمة الوحيدة هي مثيل لفئة تحتوي حقولها على المعلمات التي تتوقعها الطريقة البعيدة.
  • في [7]: الحزمة التي سيتم فيها إنشاء فئات وواجهات الوكيل C
  • في [8]: اسم الفئة المحلية التي ستعمل كوكيل للخدمة الويب البعيدة
  • في [9]: إنهاء المعالج.
  • في [10]: قائمة بالفئات والواجهات الخاصة بالوكيل C الذي تم إنشاؤه.
  • في [11]: الفئة [WsDaoJpaService] التي تنفذ أساليب الوكيل C.

تنفذ الفئة [WsDaoJpaService] التي تم إنشاؤها الواجهة [IWsDaoJpaService] التالية:


/**
 * Service.as
 * This file was auto-generated from WSDL by the Apache Axis2 generator modified by Adobe
 * Any change made to this file will be overwritten when the code is re-generated.
 */
package generated.webservices{
    import mx.rpc.AsyncToken;
    import flash.utils.ByteArray;
    import mx.rpc.soap.types.*;
               
    public interface IWsDaoJpaService
    {
        //وظائف بديلة لعملية getAllClients
        /**
         * Call the operation on the server passing in the arguments defined in the WSDL file
         * @param getAllClients
         * @return An AsyncToken
         */
        function getAllClients(getAllClients:GetAllClients):AsyncToken;
....
        function getAllClients_send():AsyncToken;
...
        function get getAllClients_lastResult():GetAllClientsResponse;
...
        function set getAllClients_lastResult(lastResult:GetAllClientsResponse):void;
...
       function addgetAllClientsEventListener(listener:Function):void;
...
        function get getAllClients_request_var():GetAllClients_request;
...
        function set getAllClients_request_var(request:GetAllClients_request):void;
...
    }
}
  • السطر 11: الواجهة [IWsDaoJpaService] التي تنفذها الفئة [WsDaoJpaService]
  • الأسطر 19-31: الطرق المختلفة التي تم إنشاؤها للطريقة getAllClients() الخاصة بخدمة الويب البعيدة. الطريقة الوحيدة التي تقترب من تلك المعروضة فعليًا بواسطة خدمة الويب هي تلك الموجودة في السطر 19. وهي تحمل الاسم الصحيح ولكنها لا تحتوي على التوقيع الصحيح: فالطريقة getAllClients() لخدمة الويب البعيدة لا تحتوي على معلمات.

المعلمة الوحيدة للطريقة getAllClients في الوكيل C الذي تم إنشاؤه هي من النوع GetAllClients التالي:


/**
 * GetAllClients.as
 * This file was auto-generated from WSDL by the Apache Axis2 generator modified by Adobe
 * Any change made to this file will be overwritten when the code is re-generated.
 */

package generated.webservices
{
    import mx.utils.ObjectProxy;
    import flash.utils.ByteArray;
    import mx.rpc.soap.types.*;
    /**
     * Wrapper class for a operation required type
     */
    
    public class GetAllClients
    {
        /**
         * Constructor, initializes the type class
         */
        public function GetAllClients() {}
            
    }
}

هذه فئة فارغة. وقد يعود ذلك إلى أن الطريقة المستهدفة getAllClients لا تقبل أي معلمات.

لنلقِ الآن نظرة على الفئات التي تم إنشاؤها للكيانات Medecin و Client و Rv و Creneau. لنلقِ نظرة، على سبيل المثال، على الفئة Client:


package generated.webservices
{
    import mx.utils.ObjectProxy;
    import flash.utils.ByteArray;
    import mx.rpc.soap.types.*;
    
    public class Client extends generated.webservices.Personne
    {
        public function Client() {}
            
    }
}

الفئة Client فارغة أيضًا. وهي مشتقة (السطر 7) من الفئة Personne التالية:


package generated.webservices
{
    import mx.utils.ObjectProxy;
    import flash.utils.ByteArray;
    import mx.rpc.soap.types.*;
    
    public class Personne
    {
        public function Personne() {}
            
        public var id:Number;
        public var nom:String;
        public var prenom:String;
        public var titre:String;
        public var version:Number;
    }
}
  • الأسطر 11-15: نجد سمات الفئة Personne المُعرَّفة ضمن خدمة الويب JEE.

لدينا الآن العناصر الرئيسية للوكيل C. يمكننا الآن استخدامه.

الملف الرئيسي [rdvmedecins01.xml] الخاص بالعميل هو التالي:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init();">
    <mx:Script>
        <![CDATA[
            import generated.webservices.Client;
...
            
            // البيانات
            private var ws:WsDaoJpaService;
            [Bindable]
            private var clients:ArrayCollection;
            
            private function init():void{
...
            }
            
            private function loadClients():void{
...
            }
            
...            
            private function displayClient(client:Client):String{
...
            } 
        ]]>
    </mx:Script>
    <mx:Label text="Liste des clients" fontSize="14"/>
    <mx:List dataProvider="{clients}" labelFunction="displayClient"></mx:List>
    <mx:Button label="Afficher les clients" click="loadClients()"/>
    <mx:Text id="txtMsgErreur" width="454" height="75"/>
    
</mx:Application>

في هذا الكود، يجب التمييز بين عدة أمور:

  • تعريف التطبيق (السطر 2)
  • وصف واجهة التطبيق (الأسطر 27-30)
  • معالجات الأحداث بلغة ActionScript داخل العلامة <mx:Script> (الأسطر 3-26).

لنبدأ بتعليق تعريف التطبيق نفسه ووصف واجهته:

  • السطر 2: يحدد
    • طريقة ترتيب المكونات داخل حاوية العرض. تشير السمة layout="vertical" إلى أن المكونات ستكون مرتبة واحدة تحت الأخرى.
    • الطريقة التي سيتم تنفيذها عند إنشاء مثيل للواجهة، c.a.d. اللحظة التي يتم فيها إنشاء مثيلات لجميع مكوناتها. تشير السمة creationComplete="init();" تشير إلى أن الطريقة init في السطر 13 هي التي يجب تنفيذها. creationComplete هي إحدى الأحداث التي يمكن أن تصدرها الفئة Application.
  • تحدد الأسطر 27-30 مكونات العرض
  • السطر 27: يحدد نصًا
  • السطر 28: قائمة سيتم إدراج قائمة العملاء فيها. تشير العلامة dataProvider="{clients}" إلى مصدر البيانات التي يجب أن تملأ القائمة. هنا، سيتم ملء القائمة بالكائن clients المُعرَّف في السطر 11. ولكي يمكن كتابة dataProvider="{clients}يجب أن يحتوي الحقل clients على السمة [Bindable] (السطر 10). تسمح هذه السمة بالإشارة إلى المتغير ActionScript خارج علامة <mx:Script>. الحقل clients هو من النوع ArrayCollection، وهو نوع ActionScript الذي يسمح بتخزين قوائم الكائنات، وفي هذه الحالة قائمة كائنات من النوع Client.
  • السطر 29: زر. يتم التعامل مع حدثه click. تشير السمة click="loadClients()" إلى أنه يجب تنفيذ الأسلوب loadClients الموجود في السطر 17 عند النقر على الزر. وسيكون هذا الزر هو الذي سيطلق الطلب إلى خدمة الويب للحصول على قائمة العملاء.
  • السطر 30: حقل نصي مخصص لعرض أي رسالة خطأ قد يرسلها الخادم استجابةً للطلب السابق.

تقوم الأسطر 27-30 بإنشاء العرض التالي في علامة التبويب [Design]:

  • [1]: تم إنشاؤه بواسطة المكون Label في السطر 27
  • [2]: تم إنشاؤه بواسطة المكون List في السطر 28
  • [3]: تم إنشاؤه بواسطة المكون Button في السطر 29
  • [4]: تم إنشاؤه بواسطة المكون Text في السطر 30
  • [5]: مثال على التنفيذ

لنلقِ نظرة الآن على الرمز ActionScript في الصفحة. يتولى هذا الرمز إدارة أحداث العرض.


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init();">

    <mx:Script>
        <![CDATA[
            import generated.webservices.Client;
...
            
            // البيانات
            private var ws:WsDaoJpaService;
            [Bindable]
            private var clients:ArrayCollection;
            
            private function init():void{
                // يتم إنشاء مثيل للوكيل الخاص بخدمة الويب
                ws=new WsDaoJpaService();
                // يتم تكوين معالجات الأحداث
                ws.addgetAllClientsEventListener(loadClientsCompleted);
                ws.addEventListener(FaultEvent.FAULT,loadClientsFault);
            }
            
            private function loadClients():void{
                // يتم طلب قائمة العملاء
                ws.getAllClients(new GetAllClients());
            }
            
            private function loadClientsCompleted(event:GetAllClientsResultEvent):void{
                // استرداد العملاء من النتيجة المرسلة
                clients=event.result as ArrayCollection;
            }
            
            private function loadClientsFault(event:FaultEvent):void{
                // يتم عرض رسالة الخطأ
                txtMsgErreur.text=event.fault.message;
            }
            
            private function displayClient(client:Client):String{
                // عرض عميل
                return client.nom + " " + client.prenom;
            } 
        ]]>
    </mx:Script>
    <mx:Label text="Liste des clients" fontSize="14"/>
    <mx:List dataProvider="{clients}" labelFunction="displayClient"></mx:List>
    <mx:Button label="Afficher les clients" click="loadClients()"/>
<mx:Text id="txtMsgErreur" width="454" height="75"/>

  • السطر 9: سيقوم ws بتعيين الوكيل C من النوع WsDaoJpaService، وهي الفئة التي تم إنشاؤها مسبقًا والتي تنفذ طرق الوصول إلى خدمة الويب البعيدة.
  • السطر 13: الطريقة init التي يتم تنفيذها عند إنشاء مثيل للعرض (السطر 1)
  • السطر 15: تم إنشاء مثيل للوكيل C
  • السطر 17: يتم ربط معالج أحداث بالحدث "انتهت الطريقة غير المتزامنة GetAllClients بنجاح". بالنسبة لأي طريقة m تابعة لخدمة الويب البعيدة، يقوم الوكيل C بتنفيذ طريقة addmEventListener التي تسمح بربط معالج بالحدث "انتهت الطريقة غير المتزامنة m بنجاح". هنا، يشير السطر 17 إلى أنه يجب تنفيذ الطريقة loadClientsCompleted الموجودة في السطر 26 عندما يتلقى عميل Flex قائمة العملاء.
  • السطر 18: يتم ربط معالج أحداث بالحدث «انتهت طريقة غير متزامنة للوكيل C بالفشل». هنا، يشير السطر 18 إلى أنه يجب تنفيذ الطريقة loadClientsFault الواردة في السطر 31 في كل مرة تفشل فيها طلبات غير متزامنة من الوكيل C إلى خدمة الويب S. وهنا، الطلب الوحيد الذي سيتم إجراؤه هو الطلب الذي يطلب قائمة العملاء.
  • في النهاية، قامت الطريقة init في السطر 13 بإنشاء مثيل للوكيل C وتعيين معالجات الأحداث للطلب غير المتزامن الذي سيتم إجراؤه لاحقًا.
  • السطر 21: الطريقة التي يتم تنفيذها عند النقر على الزر [Afficher les clients] (السطر 44)
  • السطر 23: يتم تنفيذ الطريقة غير المتزامنة getAllClients الخاصة بالوكيل C. يتم تمرير مثيل GetAllClients إليها، وهو مسؤول عن تغليف معلمات الطريقة البعيدة التي تم استدعاؤها. هنا، لا توجد أي معلمات. يتم إنشاء مثيل فارغ. الطريقة getAllClients هي طريقة غير متزامنة. يستمر التنفيذ دون انتظار البيانات التي يرسلها الخادم. ويمكن للمستخدم، على وجه الخصوص، الاستمرار في التفاعل مع العرض. وسيستمر التعامل مع الأحداث التي يثيرها. وبفضل الطريقة init، نعلم أن:
    • سيتم تنفيذ الأسلوب loadClientsCompleted (السطر 26) عندما يتلقى عميل Flex قائمة العملاء
    • سيتم تنفيذ الأسلوب loadClientsFault (السطر 31) إذا انتهى الطلب بخطأ.
  • السطر 28: يتم استرداد قائمة العملاء في الحدث. نعلم أن الطريقة getAllClients الخاصة بخدمة الويب البعيدة تُرجع قائمة. نضع هذه القائمة في الحقل clients في السطر 11. يلزم إجراء تحويل أنواع. ونظرًا لأن القائمة الموجودة في السطر 43 مرتبطة (Bindable) بحقل «العملاء»، يتم إخطارها بأن بياناتها قد تغيرت. وعندئذٍ تعرض قائمة العملاء. وستقوم بعرض كل عنصر من عناصر القائمة clients باستخدام الطريقة displayClient (السطر 43).
  • السطر 36: تتلقى الطريقة displayClient نوعًا Client. ويجب عليها إرجاع سلسلة الأحرف التي يجب أن تعرضها القائمة لهذا العميل. وهنا الاسم واللقب (السطر 38).
  • السطر 31: الطريقة التي يتم تنفيذها عند فشل طلب إلى خدمة الويب. تتلقى معلمة من النوع FaultEvent. تحتوي هذه الفئة على حقل fault الذي يغلف الخطأ الذي أرسله الخادم. fault.message هي الرسالة المصاحبة للخطأ.
  • السطر 33: يتم عرض رسالة الخطأ في منطقة النص المخصصة لهذا الغرض.

عند إنشاء التطبيق، يوجد الكود القابل للتنفيذ في المجلد [bin-debug] التابع لمشروع Flex:

فيما سبق،

  • يمثل الملف [rdvmedecins01.html] ملف HTML الذي سيطلبه المتصفح من خادم الويب للحصول على عميل Flex
  • أما الملف [rdvmedecins01.swf] فهو الملف الثنائي لعميل Flex الذي سيتم تغليفه في صفحة HTML المرسلة إلى المتصفح ثم تنفيذه بواسطة المكون الإضافي Flash Player الخاص به.

نحن جاهزون لتشغيل عميل Flex. لكن علينا أولاً إعداد بيئة التشغيل اللازمة له. لنعد إلى بنية العميل/الخادم التي تم اختبارها:

جانب الخادم:

  • تشغيل SGBD MySQL
  • تشغيل خادم Glassfish
  • ننشر خدمة الويب JEE للمواعيد إذا لم تكن منشورة
  • اختبار أحد العملاء السابقين، إن لزم الأمر، للتحقق من أن كل شيء جاهز على جانب الخادم.

على جانب العميل:

تشغيل خادم Apache الذي سيُطلب منه تشغيل تطبيق Flex. هنا نستخدم الأداة Wamp. باستخدام هذه الأداة، يمكننا ربط اسم مستعار بالمجلد [bin-debug] الخاص بمشروع Flex.

  • يوجد رمز Wamp في أسفل الشاشة [1]
  • بالنقر بزر الفأرة الأيسر على الأيقونة Wamp، حدد الخيار Apache [2] / Alias Directories [3, 4]
  • حدد الخيار [5]: إضافة اسم مستعار
  • في [6]، قم بتعيين اسم مستعار (أي اسم) للتطبيق الويب الذي سيتم تنفيذه
  • في [7] حدد جذر تطبيق الويب الذي سيحمل هذا الاسم المستعار: وهو المجلد [bin-debug] الخاص بمشروع Flex الذي أنشأناه للتو.

لنتذكر بنية المجلد [bin-debug] الخاص بمشروع Flex:

الملف [rdvmedecins01.html] هو ملف HTML الخاص بتطبيق Flex. وبفضل الاسم المستعار الذي أنشأناه للتو للمجلد [bin-debug]، يمكن الوصول إلى هذا الملف عبر عنوان URL [http://localhost/rdvmedecins/rdvmedecins01.html]. يمكننا طلب هذا الرابط في متصفح مزود بمكوّن Flash Player الإصدار 9 أو أعلى:

  • في [1]، عنوان URL لتطبيق Flex
  • في [2]، نطلب قائمة العملاء
  • في [3]، النتيجة التي نحصل عليها عندما تسير الأمور على ما يرام
  • في [4]، النتيجة التي يتم الحصول عليها عند طلب عرض العملاء في حين أن خدمة الويب قد تم إيقافها.

قد ترغب في الاطلاع على كود المصدر لصفحة HTML المستلمة

<!-- تم الحفظ من url=(0014)about:internet -->
<html lang="en">

<!-- 
Smart developers always View Source. 

This application was built using Adobe Flex, an open source framework
for building rich Internet applications that get delivered via the
Flash Player or to desktops via Adobe AIR. 

Learn more about Flex at http://flex.org 
// -->

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<!--   BEGIN قسم «سجل المتصفح» مطلوب -->
<link rel="stylesheet" type="text/css" href="history/history.css" />
<!--   END قسم "سجل المتصفح" مطلوب -->

<title></title>
<script src="AC_OETags.js" language="javascript"></script>
...
<script language="JavaScript" type="text/javascript">
<!--
// -----------------------------------------------------------------------------
// المتغيرات العالمية
// يلزم وجود الإصدار الرئيسي من Flash
var requiredMajorVersion = 9;
// يلزم وجود إصدار فرعي من Flash
var requiredMinorVersion = 0;
// الإصدار الفرعي المطلوب لبرنامج Flash
var requiredRevision = 124;
// -----------------------------------------------------------------------------
// -->
</script>
</head>

<body scroll="no">
<script language="JavaScript" type="text/javascript">
<!--
// التحقق من إصدار مشغل Flash الذي يدعم بدء تثبيت منتج المشغل (6.0r65)
....
// -->
</script>
<noscript>
        <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
                        id="rdvmedecins01" width="100%" height="100%"
                        codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
                        <param name="movie" value="rdvmedecins01.swf" />
                        <param name="quality" value="high" />
                        <param name="bgcolor" value="#869ca7" />
                        <param name="allowScriptAccess" value="sameDomain" />
                        <embed src="rdvmedecins01.swf" quality="high" bgcolor="#869ca7"
                                width="100%" height="100%" name="rdvmedecins01" align="middle"
                                play="true"
                                loop="false"
                                quality="high"
                                allowScriptAccess="sameDomain"
                                type="application/x-shockwave-flash"
                                pluginspage="http://www.adobe.com/go/getflashplayer">
                        </embed>
        </object>
</noscript>
</body>
</html>

يبدأ نص الصفحة في السطر 39. ولا يحتوي على HTML تقليدي بل على كائن (السطر 47) من النوع "application/x-shockwave-flash" (السطر 60). وهو الملف [rdvmedecins01.swf] (السطر 54) الذي يمكن رؤيته في مجلد [bin-debug] الخاص بمشروع Flex. وهو ملف كبير الحجم: حوالي 600 كيلوبايت لهذا المثال البسيط.

6.2. عميل Flex ثانٍ

لن يستخدم عميل Flex الثاني الوكيل C الذي تم إنشاؤه للعميل الأول. نريد أن نوضح أن هذه الخطوة ليست ضرورية، حتى وإن كانت تتمتع بمزايا مقارنة بالخطوة التي سيتم عرضها هنا.

يتطور المشروع على النحو التالي:

  • إلى [1] التطبيق الجديد لـ Flex
  • إلى [2] الملفات التنفيذية المرتبطة به
  • إلى [3] العرض الجديد: سنعرض قائمة الأطباء.

الرمز MXML لتطبيق [rdvmedecins02.mxml] هو كما يلي:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.ResultEvent;
            import mx.rpc.events.FaultEvent;
            import mx.collections.ArrayCollection;
            
            // البيانات
            [Bindable]
            private var medecins:ArrayCollection;
            
            private function loadMedecins():void{
                // يتم طلب قائمة الأطباء
                wsrdvmedecins.getAllMedecins.send();
            }
            
            private function loadMedecinsCompleted(event:ResultEvent):void{
                // يتم استرداد الأطباء
                medecins=event.result as ArrayCollection;
            }
            
            private function loadMedecinsFault(event:FaultEvent):void{
                // عرض رسالة الخطأ
                txtMsgErreur.text=event.fault.message;
            } 
            
            // عرض طبيب
            private function displayMedecin(medecin:Object):String{
                return medecin.nom + " " + medecin.prenom;
            } 

        ]]>
    </mx:Script>
    <mx:WebService id="wsrdvmedecins" 
        wsdl="http://localhost:8080/serveur-webservice-ejb-dao-jpa-hibernate/WsDaoJpaService?wsdl">
        <mx:operation name="getAllMedecins" 
            result="loadMedecinsCompleted(event)" fault="loadMedecinsFault(event);">
            <mx:request/>
        </mx:operation>
    </mx:WebService>
    <mx:Label text="Liste des médecins" fontSize="14"/>
    <mx:List dataProvider="{medecins}" labelFunction="displayMedecin"></mx:List>
    <mx:Button label="Afficher les médecins" click="loadMedecins()"/>
    <mx:Text id="txtMsgErreur" width="300" height="113"/>
    
</mx:Application>

لن نعلق إلا على المستجدات:

  • الأسطر 42 - 45: العرض الجديد. وهو مطابق للعرض السابق باستثناء أنه تم تكييفه لعرض الأطباء بدلاً من العملاء.
  • الأسطر 35-41: يتم هنا وصف خدمة الويب بواسطة علامة <mx:WebService> (السطر 35). لم يعد الوكيل C المستخدم في الإصدار السابق مستخدمًا هنا.
  • السطر 35: السمة id تُسمي خدمة الويب.
  • السطر 36: تحدد السمة wsdl عنوان URI لملف WSDL الخاص بخدمة الويب. وهو نفس عنوان URI الذي استخدمه العميل السابق والمحدد في الفقرة 4.10.2.
  • الأسطر 37-40: تحدد طريقة لخدمة الويب البعيدة باستخدام العلامة <mx:operation>
  • السطر 37: يتم تعريف الطريقة المشار إليها بواسطة السمة name. هنا نشير إلى الطريقة البعيدة getAllMedecins.
  • السطر 38: يتم تعريف الطرق التي يجب تنفيذها في حالة نجاح العملية (السمة result) وفي حالة الفشل (السمة fault).
  • السطر 39: تُستخدم العلامة <mx:request> لتحديد معلمات العملية. هنا، لا تحتوي الطريقة البعيدة getAllMedecins على أي معلمات، لذا لا نضع أي شيء. أما بالنسبة للطريقة التي تقبل معلمات param1 و param2، فسنكتب:
<mx:Request>
    <param1>{param1}</param1>
    <param1>{param1}</param1>
</mx:Request>

حيث تكون param1 و param2 متغيرات مُعلنة ومُهيأة في العلامة <mx:Script>

[Bindable]
private var param1:Type1;
[Bindable]
private var param2:Type2;

في العلامة <mx:Script> نجد كود ActionScript مشابهًا للكود الذي تمت دراسته في العميل السابق. والاختلاف الوحيد هو الطريقة loadMedecins في الأسطر 13-16. ويكمن الاختلاف في طريقة استدعاء الطريقة البعيدة [getAllMedecins]:

  • السطر 15: يتم استخدام خدمة الويب [wsrdvmedecins] المُعرَّفة في السطر 35 وعمليتها [getAllMedecins] المُعرَّفة في السطر 37. ولتنفيذ هذه العملية، يتم استخدام الطريقة send. وهي التي تبدأ الاستدعاء غير المتزامن للطريقة getAllMedecins الخاصة بخدمة الويب المُعرَّفة في السطر 35. وستقوم الطريقة send بإجراء الاستدعاء باستخدام المعلمات المحددة بواسطة العلامة <mx:request> في السطر 39. ولا توجد هنا أي معلمات. لو كانت الطريقة تحتوي على المعلمتين param1 و param2، لكان البرنامج النصي loadMedecins قد عيّن قيمًا لهذه المعلمات قبل استدعاء الطريقة send.

لم يتبق لنا سوى اختبار هذا التطبيق الجديد: