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> المستخدمة هنا:
اسم فئة المكون الإضافي | |
يسمح بتهيئة المكون الإضافي باستخدام أزواج (المفتاح، القيمة) |
الغرض من هذا التطبيق هو توضيح كيفية قيام المكون الإضافي باسترداد معلمات التهيئة الخاصة به وإتاحتها للكائنات الأخرى التي تشترك في نفس سياق التطبيق. سنستخدم عرض 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 {
// method called when application context is deleted
public void destroy() {
}
// method called on initial creation of application context
public void init(ActionServlet servlet, ModuleConfig conf)
throws ServletException {
// class name of this object
String className=this.getClass().getName();
// plug-in list
PlugInConfig[] pluginConfigs = conf.findPlugInConfigs();
// explore plugins to find the right one
// which is named after this class
boolean trouvé=false;
for (int i = 0; ! trouvé && i < pluginConfigs.length; i++) {
// plugin name
String pluginClassName=pluginConfigs[i].getClassName();
// if it's not the right plugin, continue
if(! pluginClassName.equals(className)) continue;
// it's the right one - you memorize its properties in context
servlet.getServletContext().setAttribute("initialisations",pluginConfigs[i].getProperties());
trouvé=true;
}//for i
} //init
} //class
يرجى ملاحظة النقاط التالية:
- تأخذ طريقة 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();
// iterate over dictionary entries
Iterator entrées = initialisations.entrySet().iterator();
while (entrées.hasNext()) {
// retrieve current input (key,value)
Map.Entry entrée = (Map.Entry) entrées.next();
String clé = (String) entrée.getKey();
String valeur = (String) entrée.getValue();
// exploit (key,value)
//...
}
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>، سيمثل العنصر العنصر الحالي في القاموس. ويمثل هذا كائن java.util.Map.Entry، وهو في الأساس زوج (مفتاح، قيمة) من القاموس.
- في نص العلامة <logic:iterate>، نعرض (<bean:write>) محتويات العنصر الحالي element. يتم التعامل مع هذا ككائن له خاصيتان: المفتاح والقيمة. يتم عرض هاتين الخاصيتين.
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:

نلاحظ أن عرض infos.jsp قد نجح في الوصول إلى المعلومات المخزنة في سياق التطبيق عبر المكون الإضافي.
8.6. الخلاصة
لقد أثبتنا أنه يمكن تهيئة تطبيق Struts باستخدام مكون إضافي. ويمكن أن يكون هذا بديلاً عن اشتقاق فئة ActionServlet لتحقيق نفس النتيجة.



