Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

 

In this tutorial, we will follow the guideline for developing a plugin to develop our Amazon S3 Datalist Binder plugin. Please also refer to the very first tutorial 如何开发一个Bean Shell Hash Variable插件 for more details steps.

1. What is the problem?

We want to retrieve the files information in Amazon S3.

2. How to solve the problem?

We can either develop a Datalist Binder 插件 or 用户界面菜单插件 for this purpose. In this tutorial, we will develop a Datalist Binder 插件 to retrieve the files information and populate it using 列表设计器.

Note

Datalist Binder is not a suitable plugin type for this purpose as the Amazon S3 Client API does not able to get the total number of files and not able to support datalist action like sort, paging and filtering. We are writing this for learning purpose and not encourage for production usage as it will have performance issue.

Better way to do this is to develop an Userview Menu which can display the file as a Tree Structure and load additional files when the tree expanded.

3. What is the input needed for your plugin?

To develop an Amazon S3 Datalist Binder plugin, we will need to provide the input as below:

  1. Amazon S3 API access key
  2. Amazon S3 API secret
  3. Amazon S3 Region
  4. Amazon S3 Bucket
  5. Folder / prefix to retrieve file list (Optional)

We will do it a little bit different here as some of the inputs will be putting in a properties file and retrieve it from the properties file when needed. Please refer to how is done in 文件上传表单元素与Amazon S3集成.

4. What is the output and expected outcome of your plugin?

A datalist which will list the files in Amazon S3 bucket based on configuration.

5. Are there any resources/API that can be reused?

We will use the AWS SDK for Java.

6. Prepare your development environment

We need to always have our Joget Workflow Source Code ready and builded by following this guideline

The following tutorial is prepared with a Macbook Pro and the Joget Source Code is version 5.0.1. Please refer to the 如何开发插件 article for other platform commands.

Let's say our folder directory is as follows. 

Code Block
- Home
  - joget
    - plugins
    - jw-community
      -5.0.1

The "plugins" directory is the folder we will create and store all our plugins and the "jw-community" directory is where the Joget Workflow Source code is stored.

Run the following command to create a maven project in "plugins" directory.

Code Block
languagebash
cd joget/plugins/
~/joget/jw-community/5.0.1/wflow-plugin-archetype/create-plugin.sh org.joget amazon_s3_datalist_binder 5.0.1

Then, the shell script will ask us to key in a version number for the plugin and ask us for a confirmation before it generates the maven project.

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

We should get a "BUILD SUCCESS" message shown in our terminal and a "amazon_s3_datalist_binder" folder created in the "plugins" folder.

Open the maven project with your favourite IDE. I will be using NetBeans.  

7. Just code it!

a. Extending the abstract class of a plugin type

Create a "AmazonS3DatalistBinder" class under "org.joget" package. Then, extend the class with org.joget.apps.datalist.model.DataListBinderDefault abstract class. Please refer to Datalist Binder 插件. We will need to implement org.joget.plugin.base.PluginWebSupport interface class as well to provide an Ajax validation in plugin properties page. Please refer to Web Service 插件.

b. Implement all the abstract methods

As usual, we have to implement all the abstract methods. We will using AppPluginUtil.getMessage method to support i18n and using constant variable MESSAGE_PATH for message resource bundle directory.

Code Block
languagejava
titleImplementation of all basic abstract methods
collapsetrue
package org.joget;
 
import org.joget.apps.app.service.AppPluginUtil;
import org.joget.apps.app.service.AppUtil;
import org.joget.apps.datalist.model.DataListBinderDefault;
import org.joget.plugin.base.PluginWebSupport;

public class AmazonS3DatalistBinder extends DataListBinderDefault implements PluginWebSupport {
    private final static String MESSAGE_PATH = "message/AmazonS3DatalistBinder";
    
    @Override
    public String getName() {
        return "Amazon S3 Datalist Binder";
    }
    @Override
    public String getVersion() {
        return "5.0.0";
    }
    
    @Override
    public String getClassName() {
        return getClass().getName();
    }
    
    @Override
    public String getLabel() {
        //support i18n
        return AppPluginUtil.getMessage("org.joget.AmazonS3DatalistBinder.pluginLabel", getClassName(), MESSAGE_PATH);
    }
    @Override
    public String getDescription() {
        //support i18n
        return AppPluginUtil.getMessage("org.joget.AmazonS3DatalistBinder.pluginDesc", getClassName(), MESSAGE_PATH);
    }
    
    @Override
    public String getPropertyOptions() {
        return AppUtil.readPluginResource(getClass().getName(), "/properties/amazonS3DatalistBinder.json", null, true, MESSAGE_PATH);
    }

}

Now, we have to create a UI for admin user to provide inputs for our plugin. In getPropertyOptions method, we already specify our 插件属性选项与配置 definition file is located at "/properties/amazonS3DatalistBinder.json". Let us create a directory "resources/properties" under "amazon_s3_datalist_binder/src/main" directory. After creating the directory, create a file named "amazonS3DatalistBinder.json" in the "properties" folder.

In the properties definition options file, we will need to provide options as below. Please note that we can use "@@message.key@@" syntax to support i18n in our properties options. As mentioned previously, some of the properties will put in a properties file, so only 1 property exist in our 插件属性选项与配置 definition file. We will have an AJAX validation to validate the properties file is exist and able to connect to Amazon S3 service.

Code Block
languagejs
[{
    title : '@@AmazonS3DatalistBinder.config@@',
    properties : [{
        name : 'folder',
        label : '@@AmazonS3DatalistBinder.folder@@',
        type : 'textfield'
    }],
    validators : [{  
        type : 'AJAX',
        url : '[CONTEXT_PATH]/web/json/app[APP_PATH]/plugin/org.joget.AmazonS3DatalistBinder/service?action=validate'
    }]
}]

Other properties will put in awsS3.properties file. This properties file will need to put in your wflow folder.

After completing the properties option to collect inputs, we can work on the main methods of the plugin which are getColumns, getPrimaryKeyColumnName, getData and getDataTotalRowCount method.

在本教程中,我们将遵循开发插件的  指南  来开发我们的Amazon S3 Datalist Binder插件。 有关更多详细信息步骤,请参阅第一个教程  如何开发一个Bean Shell哈希变量插件

1.什么问题?

我们要检索Amazon S3中的文件信息。

2.如何解决问题?

我们可以为此开发一个Datalist Binder插件用户界面菜单插件在本教程中,我们将开发一个  Datalist Binder插件  来检索文件信息并使用列表设计器填充它

Note

Datalist Binder不适合用于此目的的插件类型,因为Amazon S3客户端API无法获取文件的总数,也无法支持排序,分页和过滤等数据列表操作。我们这样写是为了学习的目的,不鼓励生产使用,因为它会有性能问题。

更好的方法是开发一个用户视图菜单,该菜单可以将文件显示为树结构,并在扩展树时加载额外的文件。

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

要开发Amazon S3 Datalist Binder插件,我们需要提供如下输入:

  1. Amazon S3 API访问密钥
  2. Amazon S3 API的秘密
  3. 亚马逊S3地区
  4. Amazon S3 Bucket
  5. 检索文件列表的文件夹/前缀(可选)

我们将在这里做一些不同的事情,因为一些输入将被放置在属性文件中,并在需要时从属性文件中检索。请参考如何在  文件上传表单元素与Amazon S3集成

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

一个数据列表,它将根据配置列出Amazon S3存储桶中的文件。

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

我们将使用适用于Java的  AWS开发工具包

6.准备你的开发环境

我们需要始终准备好我们的Joget工作流程源代码,并按照这个指导方针建立起来  。 

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

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

Code Block
- Home
  - joget
    - plugins
    - jw-community
      -5.0.1

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

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

Code Block
languagebash
cd joget/plugins/
~/joget/jw-community/5.0.1/wflow-plugin-archetype/create-plugin.sh org.joget amazon_s3_datalist_binder 5.0.1

然后,shell脚本会要求我们输入插件的版本号,并在生成maven项目之前要求我们确认。

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

我们应该在终端上显示“BUILD SUCCESS”消息,并在“plugins”文件夹中创建一个“amazon_s3_datalist_binder”文件夹。

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

7.只需编码!

a.扩展插件类型的抽象类

在“org.joget”包下创建一个“AmazonS3DatalistBinder”类。然后,使用org.joget.apps.datalist.model.DataListBinderDefault  抽象类来扩展  该类。请参阅  Datalist活页夹插件我们还需要实现  org.joget.plugin.base.PluginWebSupport  接口类,以在插件属性页面中提供Ajax验证。请参考  Web服务插件

b.实现所有的抽象方法

像往常一样,我们必须执行所有的抽象方法。我们将使用AppPluginUtil.getMessage方法来支持i18n,并使用常量变量MESSAGE_PATH作为消息资源包目录。

Code Block
languagejava
titleImplementation of all basic abstract methods
collapsetrue
package org.joget;
  
import org.joget.apps.app.service.AppPluginUtil;
import org.joget.apps.app.service.AppUtil;
import org.joget.apps.datalist.model.DataListBinderDefault;
import org.joget.plugin.base.PluginWebSupport;
 
public class AmazonS3DatalistBinder extends DataListBinderDefault implements PluginWebSupport {
    private final static String MESSAGE_PATH = "message/AmazonS3DatalistBinder";
     
    @Override
    public String getName(
Code Block
languagejava
    protected static AmazonS3 s3;
    protected static Properties properties;
    protected static DataListColumn[] columns;
    protected List<Map<String, Object>> cacheData;
 
    protected static String getPropertiesPath() {
        return SetupManager.getBaseSharedDirectory() + "awsS3.properties";
    }
    
    public static AmazonS3 getClient() throws Exception {
        if (s3 == null) {
            FileInputStream fis = null;
            try {
                properties = new Properties();
                fis = new FileInputStream(new File(getPropertiesPath()));
                properties.load(fis);
                
                BasicAWSCredentials awsCreds = new BasicAWSCredentials(properties.getProperty("access_key_id"), properties.getProperty("secret_access_key"));
                s3 = new AmazonS3Client(awsCreds);
            
            
                Region region = Region.getRegion(Regions.fromName(properties.getProperty("region")));
                s3.setRegion(region);
                
                if (!s3.doesBucketExist(properties.getProperty("bucket"))) {
                    Bucket bucket = s3.createBucket(properties.getProperty("bucket"));
                    if (bucket == null) {
                        throw new RuntimeException(AppPluginUtil.getMessage("AmazonS3DatalistBinder.bucketFilToCreate", AmazonS3DatalistBinder.class.getName(), MESSAGE_PATH));
                    }
                }
            } catch (Exception e) {
                LogUtil.error(AmazonS3DatalistBinder.class.getName(), e, "");
                s3 = null;
                
                if (e instanceof FileNotFoundException) {
                    throw new RuntimeException(AppPluginUtil.getMessage("AmazonS3DatalistBinder.configureationFileIsMissing", AmazonS3DatalistBinder.class.getName(), MESSAGE_PATH));
                } else {
                    throw e;
                }
            } finally {
                try {
                    if (fis != null) {
        return "Amazon S3 Datalist Binder";
    }
    @Override
    fis.closepublic String getVersion(); {
        return "5.0.0";
    }
     
  }
  @Override
    public String getClassName() {
       } catchreturn (Exception e) {}
getClass().getName();
    }
     
    }@Override
    public String  getLabel() }{
        return s3;//support i18n
    }
 
    protected List<Map<String, Object>> getCacheData() {return AppPluginUtil.getMessage("org.joget.AmazonS3DatalistBinder.pluginLabel", getClassName(), MESSAGE_PATH);
    }
    if (cacheData == null) {@Override
    public String getDescription() {
     cacheData = new ArrayList<Map<String, Object>>();//support i18n
        return AppPluginUtil.getMessage("org.joget.AmazonS3DatalistBinder.pluginDesc",   try {getClassName(), MESSAGE_PATH);
    }
     
    @Override
   AmazonS3 clientpublic =String getClientgetPropertyOptions(); {
        return AppUtil.readPluginResource(getClass().getName(),       String prefix = getPropertyString("folder""/properties/amazonS3DatalistBinder.json", null, true, MESSAGE_PATH);
                if (prefix.isEmpty()) }
 
}

现在,我们必须为管理员用户创建一个UI,为我们的插件提供输入。在getPropertyOptions方法中,我们已经指定了我们的  插件属性选项和配置  定义文件位于“/properties/amazonS3DatalistBinder.json”。让我们在“amazon_s3_datalist_binder / src / main”目录下创建一个目录“resources / properties”。创建目录后,在“properties”文件夹中创建一个名为“amazonS3DatalistBinder.json”的文件。

在属性定义选项文件中,我们需要提供如下的选项。请注意,我们可以在我们的属性选项中使用“@@ message.key @@”语法来支持i18n。如前所述,某些属性将放入一个属性文件中,因此我们的插件属性选项和配置  定义文件中只存在一个  属性我们将通过AJAX验证来验证属性文件是否存在并能够连接到Amazon S3服务。

Code Block
languagejs
[{
    title : '@@AmazonS3DatalistBinder.config@@',
    properties          prefix = null;: [{
        name        }: 'folder',
        label        ObjectListing listing = client.listObjects(properties.getProperty("bucket"), prefix);
: '@@AmazonS3DatalistBinder.folder@@',
        type : 'textfield'
    }],
    validators : boolean[{ cont;
        type : 'AJAX',
        url : '[CONTEXT_PATH]/web/json/app[APP_PATH]/plugin/org.joget.AmazonS3DatalistBinder/service?action=validate'
    }]
}]

其他属性将放在  awsS3.properties  文件中。这个属性文件将需要放在您的wflow文件夹中。

完成收集输入的属性选项后,我们可以使用getColumns,getPrimaryKeyColumnName,getData和getDataTotalRowCount方法来处理插件的主要方法。

Code Block
languagejava
protected static AmazonS3 s3;
protected static Properties properties;
protected static DataListColumn[] columns;
protected List<Map<String, Object>> cacheData;
 
protected static String getPropertiesPath() {do {
                    cont = false;
    return SetupManager.getBaseSharedDirectory()               + "awsS3.properties";
}
 
public static AmazonS3 getClient() throws Exception {
    if (s3 == null) {
        FileInputStream fis   List<S3ObjectSummary> summaries = listing.getObjectSummaries()null;
        try {
           for (S3ObjectSummaryproperties s= :new summariesProperties() {;
            fis = new    FileInputStream(new File(getPropertiesPath()));
      Map<String, Object> obj = new HashMap<String, Object>properties.load(fis);
             
           String BasicAWSCredentials keyawsCreds = s.getKey() new BasicAWSCredentials(properties.getProperty("access_key_id"), properties.getProperty("secret_access_key"));
            s3 = new AmazonS3Client(awsCreds);
         int pos = key.lastIndexOf("/");
         
            Region region = Region.getRegion(Regions.fromName(properties.getProperty("region")));
            objs3.put("key", keysetRegion(region);
             
           obj.put("path", (pos > 0)?(key.substring(0, pos-1)):""); if (!s3.doesBucketExist(properties.getProperty("bucket"))) {
                Bucket bucket       obj.put("filename", (pos > 0)?(key.substring(pos+1)):key= s3.createBucket(properties.getProperty("bucket"));
                if (bucket ==      obj.put("owner", s.getOwner().getDisplayName());null) {
                    throw    obj.put("md5new RuntimeException(AppPluginUtil.getMessage("AmazonS3DatalistBinder.bucketFilToCreate", sAmazonS3DatalistBinder.class.getETag(getName(), MESSAGE_PATH));
                }
        obj.put("size", s.getSize());    }
        } catch (Exception e) {
            obj.put("storageClass", s.getStorageClass())LogUtil.error(AmazonS3DatalistBinder.class.getName(), e, "");
            s3            obj.put("lastModified", s.getLastModified())= null;
             
           
 if (e instanceof FileNotFoundException) {
                throw new  cacheData.add(obj);
     RuntimeException(AppPluginUtil.getMessage("AmazonS3DatalistBinder.configureationFileIsMissing", AmazonS3DatalistBinder.class.getName(), MESSAGE_PATH));
            } else  }{
                throw    e;
            }
        if (listing.isTruncated())} finally {
            try {
           cont = true;
   if (fis != null) {
                  listing = clientfis.listNextBatchOfObjectsclose(listing);
                }
    }
        } catch (Exception e) {}
      } while (cont);}
     }
    return s3;
}
 
protected }List<Map<String, catchObject>> getCacheData(Exception e) {}
    if (cacheData == null) }{
        return cacheData;
 = new  }
 
ArrayList<Map<String, Object>>();
      public DataListColumn[] getColumns() try {
        if (columns    AmazonS3 client == nullgetClient() {;
            Collection<DataListColumn>String listprefix = new ArrayList<DataListColumn>(getPropertyString("folder");
            list.add(newif DataListColumn("key", AppPluginUtil.getMessage("AmazonS3DatalistBinder.key", getClassName(), MESSAGE_PATH), true));(prefix.isEmpty()) {
            list.add(new DataListColumn("path", AppPluginUtil.getMessage("AmazonS3DatalistBinder.path", getClassName(), MESSAGE_PATH), true))    prefix = null;
            list.add(new DataListColumn("filename", AppPluginUtil.getMessage("AmazonS3DatalistBinder.filename", getClassName(), MESSAGE_PATH), true));
}
            ObjectListing listing =   listclient.add(new DataListColumn("owner", AppPluginUtil.getMessage("AmazonS3DatalistBinder.owner", getClassName(), MESSAGE_PATH), true));
listObjects(properties.getProperty("bucket"), prefix);
            boolean  list.add(new DataListColumn("md5", AppPluginUtil.getMessage("AmazonS3DatalistBinder.md5", getClassName(), MESSAGE_PATH), false));cont;
            do {
            list.add(new DataListColumn("size", AppPluginUtil.getMessage("AmazonS3DatalistBinder.size", getClassName(), MESSAGE_PATH), true))  cont = false;
            list.add(new DataListColumn("storageClass", AppPluginUtil.getMessage("AmazonS3DatalistBinder.storageClass", getClassName(), MESSAGE_PATH), true));
            list.add(new DataListColumn("lastModified", AppPluginUtil.getMessage("AmazonS3DatalistBinder.lastModified", getClassName(), MESSAGE_PATH), true));
    List<S3ObjectSummary> summaries = listing.getObjectSummaries();
                for (S3ObjectSummary s : summaries) {
            columns    = list.toArray(new DataListColumn[]{});
  Map<String, Object> obj = new  }HashMap<String, Object>();
        return columns;
        }
 
   String publickey String= getPrimaryKeyColumnNames.getKey();
 {
        return "key";
    }
 
    public DataListCollection getData(DataList dataList, Map properties, DataListFilterQueryObject[] filterQueryObjects, String sort, Boolean desc, Integer start, Integer rows) {
int pos = key.lastIndexOf("/");
                   //TODO: handle filterQueryObjects
 obj.put("key", key);
         
        List list = PagingUtilsobj.sortAndPage(getCacheData()put("path", sort, desc, start, rows(pos > 0)?(key.substring(0, pos-1)):"");
        DataListCollection      data = new DataListCollection();
   obj.put("filename", (pos    data.addAll(list> 0)?(key.substring(pos+1)):key);
        
        return data;
    }obj.put("owner", s.getOwner().getDisplayName());
    public int getDataTotalRowCount(DataList dataList, Map properties, DataListFilterQueryObject[] filterQueryObjects) {
        //TODO: handle filterQueryObjects
obj.put("md5", s.getETag());
           
        return getCacheData().sizeobj.put("size", s.getSize());
        }

In our plugin properties, we have an AJAX validation to test the properties file and the connection to Amazon S3 Client. Let implement the webService method to provide an API for validation.

Code Block
languagexml
           public void webService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 obj.put("storageClass", s.getStorageClass());
                 boolean isAdmin = WorkflowUtilobj.isCurrentUserInRole(WorkflowUserManager.ROLE_ADMINput("lastModified", s.getLastModified());
        if (!isAdmin) {
             
                    responsecacheData.sendError(HttpServletResponse.SC_UNAUTHORIZEDadd(obj);
            return;
    }
      }
        
   
     String action = request.getParameter("action");
        if ("validate"listing.equalsisTruncated(action)) {
            String message        cont = ""true;
                   boolean successlisting = true client.listNextBatchOfObjects(listing);
            try {
   }
            } AmazonS3DatalistBinder.getClientwhile (cont);
            } catch (Exception e) {}
    }
    return cacheData;
}
 
public      LogUtil.error(this.getClassNameDataListColumn[] getColumns(), e, ""); {
    if (columns == null) {
        success = false;
        Collection<DataListColumn> list = new ArrayList<DataListColumn>();
        message = StringUtil.escapeString(e.getMessagelist.add(new DataListColumn("key", AppPluginUtil.getMessage("AmazonS3DatalistBinder.key", getClassName(), StringUtil.TYPE_JAVASCIPTMESSAGE_PATH), nulltrue));
        list.add(new    }DataListColumn("path", AppPluginUtil.getMessage("AmazonS3DatalistBinder.path", getClassName(), MESSAGE_PATH), true));
        list.add(new DataListColumn("filename", AppPluginUtil.getMessage("AmazonS3DatalistBinder.filename",  try {getClassName(), MESSAGE_PATH), true));
        list.add(new        JSONObject jsonObject = new JSONObject(DataListColumn("owner", AppPluginUtil.getMessage("AmazonS3DatalistBinder.owner", getClassName(), MESSAGE_PATH), true));
        list.add(new        jsonObject.accumulate("statusDataListColumn("md5", AppPluginUtil.getMessage("AmazonS3DatalistBinder.md5", (success?"success":"fail"getClassName(), MESSAGE_PATH), false));
                JSONArray messageArr = new JSONArray(list.add(new DataListColumn("size", AppPluginUtil.getMessage("AmazonS3DatalistBinder.size", getClassName(), MESSAGE_PATH), true));
        list.add(new DataListColumn("storageClass", AppPluginUtil.getMessage("AmazonS3DatalistBinder.storageClass", getClassName(),     messageArr.put(message);
    MESSAGE_PATH), true));
        list.add(new    jsonObject.put("message", messageArr);
DataListColumn("lastModified", AppPluginUtil.getMessage("AmazonS3DatalistBinder.lastModified", getClassName(), MESSAGE_PATH), true));
         
        jsonObject.write(response.getWriter());
       columns = list.toArray(new DataListColumn[]{});
    }
    return columns;
}
 
public String getPrimaryKeyColumnName() {
    return "key";
}
 catch
public DataListCollection getData(ExceptionDataList e) {
            dataList, Map properties, DataListFilterQueryObject[] filterQueryObjects, String sort, Boolean desc, Integer start, Integer rows) {
    //ignore
TODO: handle filterQueryObjects
     
    List }
list =       } else {PagingUtils.sortAndPage(getCacheData(), sort, desc, start, rows);
    DataListCollection data = new DataListCollection();
    responsedata.setStatus(HttpServletResponse.SC_NO_CONTENTaddAll(list);
     
   }
    }

c. Manage the dependency libraries of your plugin

We need to include "jsp-api" and "aws-java-sdk-s3" libraries in our POM file.

return data;
}
public int getDataTotalRowCount(DataList dataList, Map properties, DataListFilterQueryObject[] filterQueryObjects) {
    //TODO: handle filterQueryObjects
     
    return getCacheData().size();
}

在我们的插件属性中,我们有一个AJAX验证来测试属性文件和连接到Amazon S3客户端。让我们实现webService方法来提供一个用于验证的API。

Code Block
languagexml
 public void webService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 boolean isAdmin = WorkflowUtil.isCurrentUserInRole(WorkflowUserManager.ROLE_ADMIN);
 if (!isAdmin) {
 response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
 return;
 }
 
 String action = request.getParameter("action");
 if ("validate".equals(action)) {
 String message = "";
 boolean success = true;
 try {
 AmazonS3DatalistBinder.getClient();
 } catch (Exception e) {
 LogUtil.error(this.getClassName(), e, "");
 success = false;
 message = StringUtil.escapeString(e.getMessage(), StringUtil.TYPE_JAVASCIPT, null);
 }
 try {
 JSONObject jsonObject = new JSONObject();
 jsonObject.accumulate("status", (success?"success":"fail"));
 JSONArray messageArr = new JSONArray();
 messageArr.put(message);
 jsonObject.put("message", messageArr);
 jsonObject.write(response.getWriter());
 } catch (Exception e) {
 //ignore
 }
 } else {
 response.setStatus(HttpServletResponse.SC_NO_CONTENT);
 }
}

c.管理你的插件的依赖库

我们需要在我们的POM文件中包含“jsp-api”和“aws-java-sdk-s3”库。

Code Block
<!-- Change
Code Block
        <!-- Change plugin specific dependencies here -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-s3</artifactId>
            <version>1.10.56</version>
        </dependency>
        <!-- End change plugin specific dependencies here -->

d. Make your plugin internationalization (i18n) ready

We are using i18n message key in getLabel and getDescription method. We will use i18n message key in our properties options definition as well. Then, we will need to create a message resource bundle properties file for our plugin.


<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.0</version>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-s3</artifactId>
    <version>1.10.56</version>
</dependency>
<!-- End change plugin specific dependencies here -->

d。让你的插件国际化(国际化)

我们在getLabel和getDescription方法中使用i18n消息密钥。我们将在我们的属性选项定义中使用i18n消息密钥。然后,我们将需要为我们的插件创建一个消息资源包属性文件。

在“amazon_s3_datalist_binder / src / main”目录下创建一个目录“resources / message”。然后,在该文件夹中创建一个“AmazonS3DatalistBinder.properties”文件。在属性文件中,添加所有消息密钥及其标签,如下所示。Create a directory, "resources/message", under "amazon_s3_datalist_binder/src/main" directory. Then, create a "AmazonS3DatalistBinder.properties" file in the folder. In the properties file, add all the message keys and its label as below.

Code Block
org.joget.AmazonS3DatalistBinder.pluginLabel=Amazon S3 Datalist Binder
org.joget.AmazonS3DatalistBinder.pluginDesc=Used to retrieve the available files in Amazon S3.
AmazonS3DatalistBinder.config=Configure Amazon S3 Datalist Binder
AmazonS3DatalistBinder.configureationFileIsMissing=AWS S3 configuration file is missing.
AmazonS3DatalistBinder.bucketFilToCreate=AWS Bucket fail to create.
AmazonS3DatalistBinder.key=Key
AmazonS3DatalistBinder.path=Path
AmazonS3DatalistBinder.filename=File Name
AmazonS3DatalistBinder.owner=Owner
AmazonS3DatalistBinder.md5=MD5 Hash
AmazonS3DatalistBinder.size=Size
AmazonS3DatalistBinder.storageClass=Storage Class
AmazonS3DatalistBinder.lastModified=Last Modified
AmazonS3DatalistBinder.folder=Folder

e. Register your plugin to the Felix Framework

Last Modified
AmazonS3DatalistBinder.folder=Folder

e. 注册你的插件到Felix框架

接下来,我们将需要在Activator类(在同一个类包中自动生成)中注册我们的插件类,以告诉Felix框架这是一个插件。Next, we will have to register our plugin class in the Activator class (Auto generated in the same class package) to tell the Felix Framework that this is a plugin.

Code Block
languagejava
    public void start(BundleContext context) {
        registrationList = new ArrayList<ServiceRegistration>();
        //Register plugin here
        registrationList.add(context.registerService(AmazonS3DatalistBinder.class.getName(), new AmazonS3DatalistBinder(), null));
    }

f. Build it and test

}

f.建立它并测试

让我们建立我们的插件。构建过程完成后,我们将在“amazonLet's build our plugin. Once the building process is done, we will find a "amazon_s3_datalist_binder -5.0.0.jar" file created under "amazon/ target”目录下找到一个“amazon_s3_datalist_binder/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.

Image Removed

Check the Amazon S3 Datalist Binder plugin is available in 列表设计器.

Image Removed

Select and configure the Amazon S3 Datalist Binder.

Image Removed

Press ok. It the awsS3.properties properties file is missing or invalid. Error message will shown.

Image Removed

Design the datalist.

Image Removed

Check the result.

Image Removed

8. Take a step further, share it or sell it

-5.0.0.jar”文件。

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

Image Added

检查Amazon S3 Datalist Binder插件可在  列表设计器中找到

Image Added

选择并配置Amazon S3 Datalist活页夹。

Image Added

按下确定。它的awsS3.properties  属性文件丢失或无效。将显示错误消息。

Image Added

设计数据表。

Image Added

检查结果。

Image Added

8.再进一步,分享或出售

您可以从You can download the source code from amazon_s3_datalist_binder_src.zip.下载源代码