在本教程中, 我们将会遵循 guideline for developing a plugin 来开发我们的 Bean Shell Hash Variable 插件. 

1. 问题是什么 ?

哈希变量使用起来很方便,但有时我们想在显示一个值之前做一些条件检查。但是,哈希变量不提供条件检查的能力。

2. 如何解决这个问题?

通过查看 Joget Workflow目前支持的  插件类型,我们可以开发一个  哈希变量插件,让我们编写脚本来检查条件。有相当多的Bean Shell插件作为几种插件类型的默认插件提供。我们也可以为哈希变量插件做一个。

3. 你的插件需要什么输入信息?

哈希变量插件不提供用户配置界面,但要开发一个Bean Shell哈希变量插件,我们需要在某处放置我们的Bean Shell脚本。我们可以重新使用  环境变量  来存储我们的脚本。所以哈希变量语法将是一个环境变量键的前缀。

E.g. #beanshell.EnvironmentVariableKey#

但是,这可能还不够,我们可能还需要一些其他方法来传递一些变量。我们可以考虑使用一个URL查询参数语法来传递我们的变量,因为以后可以更容易解析。

E.g. #beanshell.EnvironmentVariableKey[name=Joget&email=info@joget.org&message={form.sample.message?url}]#

4.插件的输出和预期结果是什么?

我们期望从这个Bean Shell Hash变量插件中得到什么?Bean Shell Hash变量插件适用于管理员/开发人员用户在构建/开发应用程序时使用。一旦使用,哈希变量将被来自Bean Shell解释器的输出返回替换。以便管理员用户在向普通用户显示内容之前可以进行条件检查。

例如,显示登录用户的欢迎消息,但在用户为匿名时不显示任何内容。

5.是否有任何资源/ API可以重复使用?

要开发Bean Shell Hash变量插件,我们可以参考 所有的Hash变量插件和Bean Shell插件的  源代码。尤其是,我们可以参考环境变量哈希变量插件如何使用变量键来检索环境变量。我们也可以参考Bean Shell Tool或者Bean Shell Form Binder插件来说明如何使用Bean Shell解释器来执行脚本。 

我们可以使用StringUtil中的 getUrlParams方法  来帮助我们解析使用URL查询参数语法传入的参数。

6. 准备你的开发环境

我们需要始终准备好Joget Workflow Source Code,并按照这个指导方针建立起来。 

以下教程是使用Macbook Pro和Joget源代码5.0.0版编写的。 其他平台命令请参阅  如何开发插件文章。

假设我们的文件夹目录如下所示。 

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

“plugins”目录是我们要创建和存储我们所有插件的文件夹,“jw-community”目录是Joget Workflow源代码存储的地方。

运行以下命令在“plugins”目录下创建一个maven项目。

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

然后,shell脚本会要求我们输入插件的版本号,并在生成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”消息,在“plugins”文件夹中创建一个“beanshell_hash_variable”文件夹。

用你喜欢的IDE打开maven项目。我将使用 NetBeans。  

7. 开始编码吧!

a. 继承插件的抽象类

在“org.joget.tutorial”包下创建一个“BeanShellHashVariable”类。

然后,基于  哈希变量插件文件,我们将不得不扩展  org.joget.apps.app.model.DefaultHashVariablePlugin抽象类。

b. 实现所有的抽象方法

让我们实现所有的抽象方法。我们将使用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变量插件的主要方法,它是processHashVariable。我们将参考环境变量哈希变量插件的源代码来了解如何检索环境变量。然后,参考Bean Shell Form Binder的源代码,了解如何执行一个bean shell脚本。

    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. 管理你的插件的依赖库

我们的插件类无法解析“bsh.Interpreter”。所以,我们必须将bean shell库添加到我们的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. 让你的插件国际化(i18n)准备就绪

我们使用AppPluginUtil.getMessage方法来显示我们的getLabel和getDescription方法的i18n值。我们将不得不为它创建一个消息资源包属性文件。在“beanshell_hash_variable / src / main”目录下创建目录“resources / messages”。然后,在该文件夹中创建一个“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框架

我们将不得不在Activator类中注册我们的插件类,告诉Felix框架这是一个插件。


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 / target”目录下创建了“beanshell_hash_variable-5.0.0.jar”文件

 然后,让我们上传插件jar到  管理插件。上传jar文件后,再次检查插件是否正确上传并激活。

现在,让我们测试我们的插件。

假设我们在一个用户视图中有一个HTML菜单页面,它想把下面的行显示给登录用户。通常,我们将使用“欢迎#currentUser,用户名#”来显示欢迎消息。

但是,在这个用例中存在一个问题,当用户是匿名用户时,显示“Welcome”,没有用户名。

现在,将整个消息更改为我们的Bean Shell哈希变量,并创建一个环境变量来放置我们的脚本。

更改:

Welcome #currentUser.username#,

以下。我们将需要传递当前用户的用户名作为我们的参数之一,不要忘记把它作为url转义。

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

然后,我们可以创建一个ID为“welcome”的环境变量,并使用下面的脚本。由于我们使用StringUtil的 getUrlParams方法   来解析参数,所以参数中的所有值都是String数组。

//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. 再进一步,分享或出售

您可以从beanshell_hash_variable.zip下载源代码。

要下载现成的插件jar,请在http://marketplace.joget.org/上找到它  

  • No labels