文档章节

Writing a small plugin framework for your apps

暗之幻影
 暗之幻影
发布于 2015/03/25 15:06
字数 837
阅读 2
收藏 0

One of the most important qualities of a software is its ability or inability to be easily modified when required. One of the ways to increase modifiability is to build an architecture that allows you to add and remove components. In this post I will show you how to write a very basic pluggable framework. Extend and improve this framework and you get frameworks like JPF, the Java Plugin Framework.

Lets take a look at two basic parts of our ‘framework’.

  1. Plugin Manager Class

  2. Plugin Descriptor File

  3. Plugin Abstract Class

Plugin Manager Class

The plugin manager class is responsible for reading files that describe plugins and then loading these plugins.

package com.tksf.framework;import java.io.BufferedReader;import java.io.DataInputStream;import java.io.File;import java.io.FileInputStream;import java.io.InputStreamReader;import java.net.URI;import java.net.URL;import java.net.URLClassLoader;import java.util.ArrayList;/**
*
* @author Faheem
*
*/public class PluginManager {private static final String PLUGIN_PATH = "C://plugins/";private ArrayList plugins = new ArrayList();/**
* Load plugin descriptors from a directory location
* and then load plugin classes.
* @return
* @throws Exception
*/public ArrayList loadPlugins() throws Exception{File filePath = new File(PLUGIN_PATH);File files [] = filePath.listFiles();//Iterate over files in the plugin directoryfor(File file:files){
    if(file.isFile()){
        FileInputStream fstream = new FileInputStream(file);
        DataInputStream in = new DataInputStream(fstream);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        //read fully qualified class name of plugin from plugin descriptor file        String fullyQualifiedName = br.readLine();
        in.close();

       // Convert File to a URL       URI uri = URI.create("file:/"+PLUGIN_PATH);
       URL url = uri.toURL();
       URL[] urls = new URL[]{url};

       // Create a new class loader with the directory       ClassLoader loader = new URLClassLoader(urls);
       Class cls = loader.loadClass(fullyQualifiedName);

       //add loaded plugin to plugin list       plugins.add((Plugin)cls.newInstance());

    }else {
     //skip folders     continue;
   }}return plugins;}}

First, we define a constant which points to the file directory where plugins and their descriptors are located. Of course, you can, rather should make this path configurable instead of a constant.

private static final String PLUGIN_PATH = "C://plugins/";

In the following snippet, we load a file array that lists all files and folders from the path specified. Then, we iterate over the array, and then for each file, we read the first line. The first line is a fully qualified name of the plugin for example com.tksf.plugin.ExcelWriter.

File filePath = new File(PLUGIN_PATH);File files [] = filePath.listFiles();//Iterate over files in the plugin directoryfor(File file:files){
    if(file.isFile()){
        FileInputStream fstream = new FileInputStream(file);
        DataInputStream in = new DataInputStream(fstream);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        //read fully qualified class name of plugin from plugin descriptor file        String fullyQualifiedName = br.readLine();
        in.close();

In the next snippet, we load the class specified in the descriptor.

// Convert File to a URLURI uri = URI.create("file:/"+PLUGIN_PATH);URL url = uri.toURL();URL[] urls = new URL[]{url};// Create a new class loader with the directoryClassLoader loader = new URLClassLoader(urls);Class cls = loader.loadClass(fullyQualifiedName);

Add the loaded class to a list that is returned.

//add loaded plugin to plugin listplugins.add((Plugin)cls.newInstance());

Plugin Descriptor File

The Plugin Descriptor File is just a text file that contains one line

com.tksf.plugin.ExcelWriter

Next, we define the next part.

Plugin Abstract Class

The plugin abstract class is what defines

  1. sequence of activities that need to happen to every plugin registered.

  2. any common functionality that can be used by any plugin.

package com.tksf.framework;/**
* The abstract plugin class.
* @author Faheem
*
*/public abstract class Plugin {private String name;/**
* plugin template method
*/public void run(){
     //setting up the plugin     name = setup();
     //performing the plugin action     performAction();
     //performing cleanup actions.     tearDown();}protected abstract String setup();protected abstract void performAction();protected abstract void tearDown();}

The run method is template method. We are using the template pattern here. The run method defines what is called the ‘lifecycle’ of the plugin.

Lets now create a plugin, using our plugin framework. There are two ways of doing this however.

  1. Directly overriding plugin class

  2. Using an adapter

Directly overriding plugin class

package com.tksf.plugin;import com.tksf.framework.Plugin;public class ExcelWriter extends Plugin{

   @Override   public String setup() {
	return "Excel Writer";
   }

   @Override   public void performAction() {
	System.out.println("writing to excel");
   }

   @Override   public void tearDown() {
	System.out.println("done writing to excel.. cleaning up");
   }}

The overridden methods define plugin specific functionality. Another way however is defined below

Using an adapter

We define an adapter class that extends our Plugin class. Using this adapter, we call functions of our plugin class which does not need to extend our adapter. This allows us to have our plugins as simple POJOs that does not extend or implement any other class.

Following is an example of our adapter that calls functionality defined elsewhere.

package com.tksf.code;import com.tksf.framework.Plugin;public class Adapter extends Plugin{
    private WriteToFile object;
    
    public Adapter(WriteToFile object) {
	super();
	this.object = object;
    }

    @Override    public String setup() {
	return "Write to File";
    }

    @Override    public void performAction() {
        object.write();
    }
    
    @Override    public void tearDown() {
    }}

Finally, just write a driver class to use our plugin manager to load and use our plugins.

package com.tksf;import java.util.List;import com.tksf.framework.Plugin;import com.tksf.framework.PluginManager;public class Main {

   public Main(){
      PluginManager manager = new PluginManager();
      List plugins;
	try {
	     plugins = manager.loadPlugins();
             for(Plugin plugin:plugins){
	         plugin.run();
	      }
	     } catch (Exception e) {
	         e.printStackTrace();
	     }
	}

	public static void main(String arg[]){
	    new Main();
	}}


本文转载自:http://syntx.io/writing-a-small-plugin-framework-for-your-apps/

暗之幻影
粉丝 20
博文 377
码字总数 71245
作品 0
南京
高级程序员
私信 提问
自动化端对端测试框架-Protractor Plugins

Protractor Plugins Plugins extend Protractor's base features by using hooks during test execution to gather more data and potentially modify the test output. The Protractor API ......

dhb_oschina
2016/04/24
32
0
jQuery 的拖放操作插件集合(共25款)

本文收录了一组 jQuery 用于实现网页上的元素拖放操作的插件,介绍内容大同小异,不再翻译,大家通过截图可大概了解该插件的情况。 jquery.event.drag jquery.event.drag is an awesome jQue...

oschina
2013/03/19
15.7K
10
django-laravel-validator the laravel style data validator for django

django-laravel-validator 1. what django-laravel-validator is a django third party plugin of the purpose to validate input data easily, the easily means easy to validate , and ea......

shenyounger
2015/03/10
536
0
KDE Frameworks 5.15.0 发布

KDE Frameworks 5.15.0 发布,此版本更新内容如下: Baloo Fix limit/offset handling in SearchStore::exec Recreate the baloo index balooctl config: add options to set/view onlyBasic......

oschina
2015/10/11
1K
4
jQuery easyui 1.0.1发布

jQuery easyui framework help you build your web page easily. easyui is a collection of user-interface plugin based on jQuery. using easyui you don't write many javascript code, ......

stworthy
2010/01/27
1K
2

没有更多内容

加载失败,请刷新页面

加载更多

小知识:讲述Linux命令别名与资源文件的区别

别名 别名是命令的快捷方式。为那些需要经常执行,但需要很长时间输入的长命令创建快捷方式很有用。语法是: alias ppp='ping www.baidu.com' 它们并不总是用来缩短长命令。重要的是,你将它...

老孟的Linux私房菜
50分钟前
4
0
《JAVA核心知识》学习笔记(6. Spring 原理)-5

它是一个全面的、企业应用开发一站式的解决方案,贯穿表现层、业务层、持久层。但是 Spring 仍然可以和其他的框架无缝整合。 6.1.1. Spring 特点 6.1.1.1. 轻量级 6.1.1.2. 控制反转 6.1.1....

Shingfi
51分钟前
5
0
Excel导入数据库数据+Excel导入网页数据【实时追踪】

1.Excel导入数据库数据:数据选项卡------>导入数据 2.Excel导入网页数据【实时追踪】:

东方墨天
59分钟前
5
1
正则表达式如何匹配一个单词存在一次或零次并且不占捕获组位置

正则表达式如何匹配一个单词存在一次或零次并且不占捕获组位置 今天要用正则表达式实现匹配一个词出现一次或者不出现的情况,但是又不仅仅是这么简单的需求。先详细说下我这种情况吧,也许有...

Airship
今天
6
0
第八讲:asp.net C# web 读取文件

本讲主要讲解如何在asp.net页面上传文件。 首先,前台页面: 其次,后台页面: 结果: 1、前台效果: 2、后台结果:

刘日辉
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部