Skip to content

8. إنشاء مكون إضافي

من الممكن إنشاء تطبيقات تُسمى المكونات الإضافية (plugins) والتي يتم تحميلها عند بدء تشغيل تطبيق Struts وإلغاء تحميلها عند إيقافه. وهذا يسمح عادةً بإجراء عمليات التهيئة عند بدء تشغيل التطبيق وتحرير الموارد عند إيقافه. يمكن أيضًا إجراء هذه العمليات عن طريق اشتقاق الفئة ActionServlet من وحدة التحكم، وهذا ما تم في التطبيق السابق. يُعد المكون الإضافي بديلاً عن هذا الحل. وقد يكون المكون الإضافي تطبيقًا أكثر تعقيدًا من مجرد تهيئة البيئة. وقد رأينا مثالاً على ذلك في الدرس الذي تم فيه تقديم مفاهيم قواعد التحقق التصريحية. يتم إعلان المكون الإضافي في ملف تكوين Struts. وهكذا تم إعلان المكون الإضافي ValidatorPlugIn في الملف struts-config.xml الخاص بالتطبيق الذي كان يستخدمه:

    <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
        <set-property 
        property="pathnames" 
      value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
    />
    </plug-in>

نصف الآن تطبيق Struts يستخدم مكونًا إضافيًا.

8.1. تكوين تطبيق Struts /plugin1

نقترح إنشاء تطبيق Struts /plugin1 المُهيأ على النحو التالي:

web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <servlet>
      <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
        <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
      <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <taglib>
      <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
  </taglib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
  </taglib>

</web-app>

لن نتطرق إلى هذا الملف لأنه ملف قياسي.

struts-config.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>

    <plug-in className="istia.st.struts.plugins.MyPlugin">
        <set-property property="passwdFileName" value="data/passwd"/>
        <set-property property="groupFileName" value="data/group"/>        
    </plug-in>

</struts-config>

لم ندرج سوى قسم واحد، وهو القسم الخاص بالمكوّن الإضافي. فيما يلي سمات العلامة <plug-in> المستخدمة هنا:

className
اسم فئة المكون الإضافي
<set-property>
يسمح بتهيئة المكون الإضافي باستخدام أزواج (مفتاح، قيمة)

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

8.2. فئة Java الخاصة بالمكوّن الإضافي

يجب أن تقوم فئة Java تُستخدم كمكوّن إضافي لتطبيق Struts بتنفيذ الواجهة org.apache.struts.action.PlugIn. ويتمثل هذا التنفيذ في كتابة طريقتين:

  • public void init(ActionServlet servlet, ModuleConfig conf)
  • public void destroy()

عند تحميل تطبيق Struts، سيقوم وحدة التحكم الخاصة به بإنشاء مثيلات لجميع المكونات الإضافية المُعلنة في الملف struts-config.xml. ثم سيقوم بتنفيذ طريقة init لكل منها. وفي هذه الطريقة يقوم المكون الإضافي بإجراء عمليات التهيئة الخاصة به. هنا، سنكتفي بقراءة معلمات التهيئة الخاصة بالمكوّن الإضافي ووضعها في سياق التطبيق حتى تكون متاحة لجميع الكائنات الأخرى فيه. وعندما يتم إلغاء تحميل التطبيق، سيقوم وحدة التحكم بتنفيذ طريقة destroy لكل مكوّن إضافي تم تحميله. وهذا هو الوقت المناسب لتحرير الموارد التي أصبحت غير ضرورية. هنا، لن يكون لدينا ما نفعله.

فيما يلي كود الفئة:

package istia.st.struts.plugins;

import javax.servlet.ServletException;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.config.PlugInConfig;

public class MyPlugin implements PlugIn {

    // الطريقة التي يتم استدعاؤها عند حذف سياق التطبيق
    public void destroy() {
    }

     // تم استدعاء الطريقة عند الإنشاء الأولي لسياق التطبيق
    public void init(ActionServlet servlet, ModuleConfig conf)
        throws ServletException {
         // اسم فئة هذا الكائن
        String className=this.getClass().getName();
        // قائمة المكونات الإضافية
        PlugInConfig[] pluginConfigs = conf.findPlugInConfigs();
         // البحث في المكونات الإضافية للعثور على المكون الإضافي
         // الذي يحمل اسم هذه الفئة
        boolean trouvé=false;
        for (int i = 0; ! trouvé && i < pluginConfigs.length; i++) {
            // اسم المكون الإضافي
            String pluginClassName=pluginConfigs[i].getClassName();
             // إذا لم يكن هذا هو المكون الإضافي الصحيح، نواصل البحث
            if(! pluginClassName.equals(className)) continue;
            // إنه المكون الإضافي الصحيح - نقوم بتخزين خصائصه في السياق
            servlet.getServletContext().setAttribute("initialisations",pluginConfigs[i].getProperties());
            trouvé=true;
        }//for i
    } //التهيئة
} //فئة

يرجى ملاحظة النقاط التالية:

  • تستقبل الطريقة init معلمة تُسمى هنا conf من النوع ModuleConfig والتي تتيح الوصول إلى محتوى الملف struts-config.xml.
  • تسمح الطريقة [ModuleConfig].findPlugInConfigs() باسترداد جميع أقسام <plug-in> من ملف تكوين Struts في شكل مصفوفة من كائنات PlugInConfig.
  • تمثل الفئة PluginConfig قسم <plug-in> من ملف التكوين. تتيح لنا الطريقة [PlugInConfig].getProperties الوصول إلى عناصر <set-property> في القسم في شكل قاموس java.util.Map.
  • يتم وضع قاموس خصائص المكون الإضافي في سياق التطبيق.
  • ونظرًا لإمكانية وجود عدة مكونات إضافية، يتعين علينا تحديد المكون الذي يهمنا. وهو المكون الذي يحمل نفس اسم الفئة التي يتم تنفيذها.

وقد فضلنا هنا وضع القاموس بالكامل في السياق. كان بإمكاننا الاستفادة من هذا القاموس. توضح سلسلة التعليمات البرمجية التالية إحدى طرق القيام بذلك:

            Map initialisations = pluginConfigs[i].getProperties();
             // التكرار على إدخالات القاموس
            Iterator entrées = initialisations.entrySet().iterator();
            while (entrées.hasNext()) {
                 // استرداد المدخل (المفتاح، القيمة) الحالي
                Map.Entry entrée = (Map.Entry) entrées.next();
                String clé = (String) entrée.getKey();
                String valeur = (String) entrée.getValue();
                // معالجة (المفتاح، القيمة)
                //...
            }

8.3. رمز العرض infos.jsp

تتولى طريقة العرض infos.jsp عرض محتوى قاموس خصائص المكون الإضافي الذي تم وضعه في سياق التطبيق. وبما أن طريقة العرض infos.jsp جزء من هذا السياق، فإنها تتمتع بإمكانية الوصول إليه. وفيما يلي كودها:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
    <head>
        <title>Plugin</title>
    </head>
    <body>
        <h3>Infos du plugin<br></h3>
        <table border="1">
            <tr>
                <th>Clé</th><th>Valeur</th>
            </tr>            
            <logic:iterate id="element" name="initialisations">
                <tr>
                    <td><bean:write name="element" property="key"/></td>
                    <td><bean:write name="element" property="value"/></td>
                </tr>
            </logic:iterate>
        </table>
    </body>
</html>

ملاحظات:

  • نستخدم مكتبات العلامات struts-logic و struts-bean
  • تسمح لنا العلامة <logic:iterate> بعرض قاموس التهيئة الذي تم وضعه في السياق بواسطة طريقة init الخاصة بالمكوّن الإضافي. يشير السمة name إلى الكائن الذي يجب التكرار عليه. يجب أن يكون هذا الكائن شبيهاً بمجموعة أو متكرر أو ما شابه. يتم البحث عن الكائن في جميع نطاقات (الصفحة، الطلب، الجلسة، السياق). وهنا سيتم العثور عليه في نطاق السياق. تُستخدم المعلمة id لتسمية العنصر الحالي في المجموعة خلال عمليات التكرار. هنا، في نص العلامة <logic:iterate>، سيمثل element العنصر الحالي في قاموس. ويمثل هذا العنصر كائن java.util.Map.Entry الذي يُعد بشكل عام زوجًا (مفتاح، قيمة) من القاموس.
  • في جسم العلامة <logic:iterate>، يتم عرض (<bean:write>) محتوى العنصر الحالي element. ويُعتبر هذا العنصر كائنًا له خاصيتان (property): المفتاح key والقيمة value. ويتم عرض هاتين الخاصيتين.

8.4. النشر

يتم تعريف سياق التطبيق في ملف التكوين server.xml الخاص بـ Tomcat:

<Context path="/plugin11" reloadable="true" docBase="E:\data\serge\web\struts\plugins\1" />

هيكل التطبيق كالتالي:

 
 

8.5. الاختبارات

نقوم بتشغيل Tomcat ونطلب URL http://localhost:8080/plugin1/infos.jsp:

Image

نلاحظ أن العرض infos.jsp قد تمكن بالفعل من الوصول إلى المعلومات المخزنة في سياق التطبيق بواسطة المكون الإضافي.

8.6. الخلاصة

لقد أظهرنا أنه يمكن تهيئة تطبيق Struts باستخدام مكون إضافي. وقد يكون هذا حلاً بديلاً عن اشتقاق الفئة ActionServlet للقيام بنفس المهمة.