ในบทนี้ เราจะทำตาม guideline for developing a plugin เพื่อพัฒนาปลั๊กอิน Bean Shell Hash Variable ของเรา 

1. ปัญหาคืออะไร?

Hash variable สะดวกในการใช้งาน แต่บางครั้งเราต้องการตรวจสอบางเงื่อนไขก่อนที่จะแสดงค่า แต่ตัวแปร Hash variable ไม่สามารถตรวจสอบได้

2.ความคิดของคุณในการแก้ปัญหาคืออะไร?

โดยดูที่ Plugin Types ได้ที่รับการสนับสนุนโดย Joget Workflow เราสามารถพัฒนา Hash Variable Plugin เพื่อให้เราสามารถเขียนสคริปต์เพื่อตรวจสอบเงื่อนไขได้ มีปลั๊กอิน Bean Shell จำนวนหนึ่งที่ให้ไว้เป็นปลั๊กอินเริ่มต้นสำหรับปลั๊กอินหลายประเภท เราสามารถทำปลั๊กอิน Hash Variable ได้เช่นกัน

3. อินพุตที่จำเป็นสำหรับปลั๊กอินของคุณคืออะไร?

ปลั๊กอิน Hash Variable  ไม่มีส่วนต่อประสานสำหรับผู้ใช้ในการกำหนดค่า แต่เพื่อการพัฒนาปลั๊กอิน Bean Shell Hash Variable เราต้องการใส่ Bean Shell script ของเรา เราสามารถนำ Environment Variable มาใช้ใหม่เพื่อจัดเก็บสคริปต์ของเรา ดังนั้นไวยากรณ์ Hash Variable จะเป็นคำนำหน้าด้วยคีย์ตัวแปรสภาพแวดล้อม

เช่น. #beanshell.EnvironmentVariableKey#

แต่นี่อาจไม่เพียงพอ เราอาจต้องการวิธีอื่นในการส่งผ่านตัวแปรบางตัวเช่นกัน เราสามารถพิจารณาการใช้ไวยากรณ์พารามิเตอร์การสืบค้น URL เพื่อส่งผ่านตัวแปรของเราเพราะง่ายต่อการแยกวิเคราะห์ในภายหลัง

เช่น. #beanshell.EnvironmentVariableKey[name=Joget&email=info@joget.org&message={form.sample.message?url}]#

4. ผลลัพธ์และผลลัพธ์ที่คาดหวังของปลั๊กอินของคุณคืออะไร?

เราคาดหวังอะไรจากปลั๊กอิน Bean Shell Hash variable? ปลั๊กอิน Bean Shell Hash Variable ใช้สำหรับ admin/developer user ที่จะใช้เมื่อ building/developing แอป. เมื่อใช้แล้ว ตัวแปร Hash Variable จะถูกแทนที่ด้วยผลลัพธ์ที่ส่งคืนจาก Bean Shell interpreter. เพื่อให้ผู้ใช้ที่เป็นผู้ดูแลระบบสามารถทำการตรวจสอบสภาพก่อนที่จะแสดงบางสิ่งกับผู้ใช้ปกติ

เช่น แสดงข้อความต้อนรับสำหรับผู้ใช้ที่ล็อกอิน แต่ไม่แสดงสิ่งนี้เมื่อผู้ใช้ไม่ระบุชื่อ

5. มีทรัพยากร / API ใด ๆ ที่สามารถนำกลับมาใช้ใหม่ได้หรือไม่?

เพื่อการพัฒนาปลั๊กอิน Bean Shell Hash Variable  เราสามารถอ้างอิงถึง source code จากทั้งหมดปลั๊กอิน Hash Variable และปลั๊กอิน Bean Shell Especially, เราสามรถอ้างอิงถึงตัวแปรปลั๊กอิน Environment Variable Hash Variable  เกี่ยวกับวิธีเรียกข้อมูลตัวแปร environment variable โดยใช้ตัวแปร variable key. เราสามารถอ้างอิงถึง Bean Shell Tool หรือปลั๊กอิน Bean Shell Form Binder  สิ่งที่จะรันสคริปต์ด้วย Bean Shell interpreter. 

เราสามารถใช้วิธี getUrlParams method ได้ จาก StringUtil เพื่อช่วยเราวิเคราะห์ parameters ที่ส่งผ่านด้วย URL query parameters syntax.

6. เตรียม environment ของคุณเพื่อการพัฒนา

เราจำเป็นต้องมี Joget Workflow Source Code ให้พร้อม และสร้างโดยทำตาม this guideline นี้

บทช่วยสอนต่อไปนี้จัดทำขึ้นด้วย Macbook Pro และ Joget Source Code version 5.0.0. โปรดดูที่ แนวทางสำหรับการพัฒนาปลั๊กอิน บทความสำหรับคำสั่งแพลตฟอร์มอื่น ๆ

สมมติว่าไดเรกทอรีโฟลเดอร์ของเรามีดังต่อไปนี้

- Home
  - joget
    - plugins
    - jw-community
      -5.0.0

The "plugins" directory คือโฟลเดอร์ที่เราจะสร้างและจัดเก็บปลั๊กอินทั้งหมดของเราและ "jw-community" directory คือที่เก็บซอร์สโค้ด Joget Workflow

เรียกใช้คำสั่งต่อไปนี้เพื่อสร้างโครงการ maven ในไดเรกทอรี "plugins"

cd joget/plugins/
~/joget/jw-community/5.0.0/wflow-plugin-archetype/create-plugin.sh org.joget.tutorial beanshell_hash_variable 5.0.0

จากนั้น the shell script จะขอให้เราใส่หมายเลขเวอร์ชันสำหรับปลั๊กอินและขอให้เรายืนยันก่อนที่จะสร้างโครงการ Maven

Define value for property 'version':  1.0-SNAPSHOT: : 5.0.0
[INFO] Using property: package = org.joget.tutorial
Confirm properties configuration:
groupId: org.joget.tutorial
artifactId: beanshell_hash_variable
version: 5.0.0
package: org.joget.tutorial
Y: : y

เราควรได้รับข้อความ "BUILD SUCCESS" ที่แสดงใน terminal ของเราและ "beanshell_hash_variable" สร้างโฟลเดอร์ใน "plugins" folder.

เปิด maven project ของคุณด้วย IDE ที่ชื่นชอบ. เราแนะนำ NetBeans.  

7. เริ่มโค้ด!

a. การขยาย abstract class ของประเภทปลั๊กอิน

สร้าง "BeanShellHashVariable" ภายใต้ class "org.joget.tutorial" package.

จากนั้น ขึ้นอยู่กับเอกสาร Hash Variable Plugin ,เราจะต้องขยาย org.joget.apps.app.model.DefaultHashVariablePlugin abstract class.

b. การดำเนินการของ abstract methods ทั้งหมด

ให้เราใช้วิธีนามธรรมทั้งหมด เราจะใช้วิธี AppPluginUtil.getMessage เพื่อสนับสนุน i18n และการใช้ตัวแปร MESSAGE_PATH แบบคงที่สำหรับไดเร็กทอรีบันเดิลทรัพยากรข้อความ

Implementation of all basic abstract methods
package org.joget.tutorial;
 
import org.joget.apps.app.model.DefaultHashVariablePlugin;
import org.joget.apps.app.service.AppPluginUtil;
 
public class BeanShellHashVariable extends DefaultHashVariablePlugin {
    
    private final static String MESSAGE_PATH = "messages/BeanShellHashVariable";
 
    public String getName() {
        return "BeanShellHashVariable";
    }
 
    public String getVersion() {
        return "5.0.0";
    }
 
    public String getClassName() {
        return getClass().getName();
    }
    
    public String getLabel() {
        //support i18n
        return AppPluginUtil.getMessage("org.joget.tutorial.BeanShellHashVariable.pluginLabel", getClassName(), MESSAGE_PATH);
    }
    
    public String getDescription() {
        //support i18n
        return AppPluginUtil.getMessage("org.joget.tutorial.BeanShellHashVariable.pluginDesc", getClassName(), MESSAGE_PATH);
    }
 
    public String getPropertyOptions() {
        //Hash variable plugin do not support property options
        return "";
    }
    
    public String getPrefix() {
        return "beanshell";
    }
    
    public String processHashVariable(String variableKey) {
        throw new UnsupportedOperationException("Not supported yet."); 
    }
}

ตอนนี้ เรามาดูวิธีการหลักของปลั๊กอิน Hash Variable ซึ่งเป็น processHashVariable. เราจะอ้างถึง source code ของ Environment Variable Hash Variable plugin เกี่ยวกับวิธีดึงข้อมูล Environment variable. จากนั้น, อ้างถึง source code ของ Bean Shell Form Binder เกี่ยวกับการดำเนินการ bean shell script.

    public String processHashVariable(String variableKey) {
        try {
            String environmentVariableKey = variableKey;
            
            //first check and retrieve parameters passed in with URL query parameters syntax wrapped in square bracket []
            String queryParams = null;
            if (variableKey.contains("[") && variableKey.contains("]")) {
                queryParams = variableKey.substring(variableKey.indexOf("[") + 1, variableKey.indexOf("]"));
                environmentVariableKey = variableKey.substring(0, variableKey.indexOf("["));
            }
 
            //Parse the query parameters to a map
            Map<String, String[]> parameters = null;
            if (queryParams != null && !queryParams.isEmpty()) {
                parameters = StringUtil.getUrlParams(queryParams);
                
                //put all parameters to plugin properties
                getProperties().putAll(parameters);
            }
 
            //Retrieve the environment variable based on environmentVariableKey
            AppDefinition appDef = (AppDefinition) getProperty("appDefinition");
            if (appDef != null) {
                ApplicationContext appContext = AppUtil.getApplicationContext();
                EnvironmentVariableDao environmentVariableDao = (EnvironmentVariableDao) appContext.getBean("environmentVariableDao");
                EnvironmentVariable env = environmentVariableDao.loadById(environmentVariableKey, appDef);
                if (env != null) {
                    String script = env.getValue();
                    //execute the script with all plugin properties
                    return executeScript(script, getProperties());
                } else {
                    //environment variable not found, return empty value
                    return "";
                }
            }
        } catch (Exception e) {
            //log the exception using LogUtil
            LogUtil.error(getClassName(), e, "#beanshell."+variableKey+"# fail to parse.");
        }
        
        //return null to by pass the replacing
        return null;
    }
    
    protected String executeScript(String script, Map properties) throws Exception {
        Interpreter interpreter = new Interpreter();
        interpreter.setClassLoader(getClass().getClassLoader());
        for (Object key : properties.keySet()) {
            interpreter.set(key.toString(), properties.get(key));
        }
        LogUtil.debug(getClass().getName(), "Executing script " + script);
        return (String) interpreter.eval(script);
    }

c. จัดการ dependency libraries ปลั๊กอินของคุณ

คลาสปลั๊กอินของเราไม่สามารถแก้ไขได้ "bsh.Interpreter". ดังนั้นเราจะต้องเพิ่ม bean shell library ในไฟล์ POM ของเรา

<!-- Change plugin specific dependencies here -->
<dependency>
    <groupId>org.beanshell</groupId>
    <artifactId>bsh</artifactId>
    <version>2.0b4</version>
</dependency>
<!-- End change plugin specific dependencies here -->

d. เตรียมปลั๊กอิน internationalization (i18n) ให้พร้อม

เรากำลังใช้ AppPluginUtil.getMessage method เพื่อแสดง i18n value สำหรับ getLabel และ getDescription method ของเรา. เราจะต้องสร้างไฟล์คุณสมบัติทรัพยากรสำหรับมัน Create directory "resources/messages" ภายใต้"beanshell_hash_variable/src/main" directory. ดังนั้น สร้างไฟล์ "BeanShellHashVariable.properties" ในโฟลเดอร์

ในไฟล์คุณสมบัติของเราเราจะต้องเพิ่มคีย์ที่เราใช้ ลงไป

org.joget.tutorial.BeanShellHashVariable.pluginLabel=Bean Shell Hash Variable
org.joget.tutorial.BeanShellHashVariable.pluginDesc=Using environment variable to execute bean shell script.

e. ลงทะเบียนปลั๊กอินของคุณไปที่ Felix Framework

เราจะต้องลงทะเบียนคลาสปลั๊กอินของเราในคลาส Activator เพื่อบอก Felix Framework ว่านี่คือปลั๊กอิน


public void start(BundleContext context) {
    registrationList = new ArrayList<ServiceRegistration>();

    //Register plugin here
    registrationList.add(context.registerService(BeanShellHashVariable.class.getName(), new BeanShellHashVariable(), null));
}

f. สร้างและทดสอบ

ให้สร้างปลั๊กอินของเรา เมื่อกระบวนการสร้างเร็จสิ้น เราจะพบไฟล์ "beanshell_hash_variable-5.0.0.jar" สร้างขึ้นภายใน "beanshell_hash_variable/target" directory.

 Then, let's upload the plugin jar to Manage Plugins. After uploading the jar file, double check that the plugin is uploaded and activated correctly.

ตอนนี้ ลองทดสอบปลั๊กอินของเรา

สมมติว่าเรามีหน้าเมนู HTML ใน userview ที่ต้องการแสดงบรรทัดต่อไปนี้เพื่อเข้าสู่ระบบผู้ใช้ โดยปกติเราจะใช้ "ยินดีต้อนรับ # currentUser ชื่อผู้ใช้ #" เพื่อแสดงข้อความต้อนรับ

แต่ในกรณีการใช้งานนี้มีปัญหาซึ่งแสดง "ยินดีต้อนรับ" โดยไม่มีชื่อผู้ใช้เมื่อผู้ใช้ไม่ระบุชื่อ

ตอนนี้เปลี่ยนข้อความทั้งหมดเป็น Bean Shell Hash Variable ของเราและสร้างตัวแปรสภาพแวดล้อมเพื่อใส่สคริปต์ของเรา

เปลี่ยน:

Welcome #currentUser.username#,

ต่อไปนี้ เราจะต้องส่งชื่อผู้ใช้ของผู้ใช้ปัจจุบันเป็นหนึ่งในพารามิเตอร์ของเราและอย่าลืมที่จะหลีกเลี่ยงมันเป็น URL

#beanshell.welcome[username={currentUser.username?url}]?html#

จากนั้นเราสามารถสร้างตัวแปรสภาพแวดล้อมด้วย ID "ยินดีต้อนรับ" และใช้สคริปต์ต่อไปนี้ ในขณะที่เรากำลังใช้วิธี getUrlParams จาก StringUtil เพื่อแยกพารามิเตอร์ค่าทั้งหมดจากพารามิเตอร์คืออาร์เรย์สตริง

//all parameters passed in from Beanshell Hash Variable will converted to String array 
if (username != null && username.length == 1 && !username[0].isEmpty()) {
    return "Welcome " + username[0] + ",";
} else {
    return ""; 
}

ให้กลับไปที่หน้าเมนู HTML ของเราเพื่อดูผลลัพธ์

เมื่อผู้ใช้เข้าสู่ระบบจะแสดงข้อความอย่างถูกต้อง

เมื่อไม่มีผู้ใช้ที่ล็อกอินข้อความต้อนรับจะไม่ปรากฏขึ้น

8. ขั้นต่อไป แชร์หรือขาย

คุณสามารถดาวน์โหลด source code จาก beanshell_hash_variable.zip.

หากต้องการดาวน์โหลด jar ปลั๊กอินที่พร้อมใช้งานโปรดค้นหา http://marketplace.joget.org/.

  • No labels