如果一个搜索引擎仅仅是网页搜索,那么将会是非常枯燥的,也不能根据业务需求扩展,还好Iveely在设计之初,就考虑了扩展性,预留插件功能,在不关闭服务或者停用服务的情况下,可以随时启用新插件或者禁用。

首先先介绍下Iveely加载插件的流程,再举例一步一步写插件。

原理

在Iveely.Service下面,存在一个plugin.json文件,Iveely.Service将会每六个小时,更新配置信息,如果plugin.json有更新,将会更新到系统中。Iveey.Service只是一个服务中转站,它将用户的请求,根据请求的命令或者匹配的规则,将请求数据转发给对应插件进行处理,最终将插件处理后的结果返回给用户。plugin.json详细信息介绍如下:

plugin.json文件示例

{
"emailServer":"smtp.126.com",
"emailPort":"25",
"emailName":"Iveely后台服务",
"email": "2@126.com",
"password": "2",
"notify": "liufanping@iveely.com,founder@iveely.com",
"plugins": [
{
"name": "天气预报",
"enable": "1",
"pattern": ".*天气.*",
"command": "weather",
"executeType":"1",
"owner": "1@qq.com",
"ip": "1.iveely.com,5001",
"backup": "1.iveely.com,5001"
},
{
"name": "计算器",
"enable": "1",
"pattern": ".*等于.*",
"command": "calculate",
"executeType":"2",
"owner": "2@qq.com",
"ip": "2.iveely.com,5002",
"backup": "2.iveely.com,5002"
}]
}

下面将以搜索引擎的计算功能为例,为Iveely新增计算插件,首先效果图如下:

     示例

第一步:新建纯Java应用程序工程。

第二步:添加相应的库。

由于插件是以网络方式存在的,因此添加必要的网络库是必然的,其次是基于Iveely.Framework存在。

这些jar文件,均可以在Iveely.Framework工程中找到。

第三步:编写计算器计算类:Calculate类。

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.iveely.plugins.calculator; import java.util.Collections;
import java.util.Stack; /**
*
* @author X1 Carbon
*/
public class Calculate { /**
* Algorithm helper.
*
* @author liufanping@iveely.com
* @date 2014-11-16 10:38:07
*/
public static class ArithHelper { /**
* The default precision division.
*/
private static final int DEF_DIV_SCALE = 16; private ArithHelper() {
} /**
* Provide accurate addition.
*
* @param v1
* @param v2
* @return
*/
public static double add(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
} /**
* Provide accurate addition.
*
* @param v1
* @param v2
* @return
*/
public static double add(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.add(b2).doubleValue();
} /**
* Provide accurate subtraction.
*
* @param v1
* @param v2
* @return
*/
public static double sub(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
} /**
* Provide accurate subtraction.
*
* @param v1
* @param v2
* @return
*/
public static double sub(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.subtract(b2).doubleValue();
} /**
* Provides accurate multiplication.
*
* @param v1
* @param v2
* @return
*/
public static double mul(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
} /**
* Provides accurate multiplication.
*
* @param v1
* @param v2
* @return
*/
public static double mul(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.multiply(b2).doubleValue();
} /**
* Provide (relatively) precise division, except when the situation
* occurs when the endless, accurate to 10 decimal point, after the
* figures are rounded.
*
* @param v1
* @param v2
* @return
*/
public static double div(double v1, double v2) {
return div(v1, v2, DEF_DIV_SCALE);
} /**
* Provide (relatively) precise division, except when the situation
* occurs when the endless, accurate to 10 decimal point, after the
* figures are rounded.
*
* @param v1
* @param v2
* @return
*/
public static double div(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.divide(b2, DEF_DIV_SCALE, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
} /**
* Providing (relatively) accurate division. When occurrence except
* endless, specify the scale parameter accuracy, after rounding
* numbers.
*
* @param v1
* @param v2
* @param scale。
* @return
*/
public static double div(double v1, double v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.divide(b2, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
} /**
* Provides precise decimals rounded handle.
*
* @param v
* @param scale
* @return
*/
public static double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b = new java.math.BigDecimal(Double.toString(v));
java.math.BigDecimal one = new java.math.BigDecimal("1");
return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
} /**
* Provides precise decimals rounded handle.
*
* @param v
* @param scale
* @return
*/
public static double round(String v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b = new java.math.BigDecimal(v);
java.math.BigDecimal one = new java.math.BigDecimal("1");
return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}
} /**
* Postfix stack.
*/
private final Stack<String> postfixStack; /**
* Operator Stack.
*/
private final Stack<Character> opStack; /**
* Operators use the ASCII -40 indexing of operator precedence.
*/
private final int[] operatPriority; public Calculate() {
postfixStack = new Stack<>();
opStack = new Stack<>();
operatPriority = new int[]{0, 3, 2, 1, -1, 1, 0, 2};
} /**
* According to the given expression evaluates.
*
* @param expression
* @return
*/
public String calculate(String expression) {
try {
Stack<String> resultStack = new Stack<>();
prepare(expression);
Collections.reverse(postfixStack);
String firstValue, secondValue, currentValue;
while (!postfixStack.isEmpty()) {
currentValue = postfixStack.pop();
if (!isOperator(currentValue.charAt(0))) {
resultStack.push(currentValue);
} else {
secondValue = resultStack.pop();
firstValue = resultStack.pop();
String tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
resultStack.push(tempResult);
}
}
return expression + "=" + Double.valueOf(resultStack.pop());
} catch (NumberFormatException e) {
}
return "";
} /**
* Be converted into postfix expression stack.
*
* @param expression
*/
private void prepare(String expression) {
opStack.push(',');
char[] arr = expression.toCharArray();
int currentIndex = 0;
int count = 0;
char currentOp, peekOp;
for (int i = 0; i < arr.length; i++) {
currentOp = arr[i];
if (isOperator(currentOp)) {
if (count > 0) {
postfixStack.push(new String(arr, currentIndex, count));
}
peekOp = opStack.peek();
if (currentOp == ')') {
while (opStack.peek() != '(') {
postfixStack.push(String.valueOf(opStack.pop()));
}
opStack.pop();
} else {
while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) {
postfixStack.push(String.valueOf(opStack.pop()));
peekOp = opStack.peek();
}
opStack.push(currentOp);
}
count = 0;
currentIndex = i + 1;
} else {
count++;
}
}
if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {
postfixStack.push(new String(arr, currentIndex, count));
}
while (opStack.peek() != ',') {
postfixStack.push(String.valueOf(opStack.pop()));
}
} /**
* Determine whether the arithmetic sign.
*
* @param c
* @return
*/
private boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
} /**
* Use ASCII code -40 subscript to do arithmetic signs priority.
*
* @param cur
* @param peek
* @return
*/
public boolean compare(char cur, char peek) {
boolean result = false;
if (operatPriority[(peek) - 40] >= operatPriority[(cur) - 40]) {
result = true;
}
return result;
} /**
* According to the given arithmetic operators to do the calculation.
*
* @param firstValue
* @param secondValue
* @param currentOp
* @return
*/
private String calculate(String firstValue, String secondValue, char currentOp) {
String result = "";
switch (currentOp) {
case '+':
result = String.valueOf(ArithHelper.add(firstValue, secondValue));
break;
case '-':
result = String.valueOf(ArithHelper.sub(firstValue, secondValue));
break;
case '*':
result = String.valueOf(ArithHelper.mul(firstValue, secondValue));
break;
case '/':
result = String.valueOf(ArithHelper.div(firstValue, secondValue));
break;
default:
result = "error format.";
}
return result;
}
}

Calculate类是用于服务的,那么它是怎么提供对外服务呢?

第四步:新建EventHandler类:用于消息处理。

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.iveely.plugins.calculator; import com.iveely.framework.net.ICallback;
import com.iveely.framework.net.InternetPacket;
import java.io.UnsupportedEncodingException; /**
*
* @author 凡平
*/
public class EventHandler implements ICallback { /**
* Weather forecast.
*/
private Calculate calculate; public EventHandler() {
this.calculate = new Calculate();
} @Override
public InternetPacket invoke(InternetPacket packet) {
InternetPacket respPacket = new InternetPacket();
respPacket.setMimeType(0);
respPacket.setExecutType(packet.getExecutType() * -1);
if (packet.getExecutType() == 2) {
try {
String query = getString(packet.getData());
System.out.println("计算表达式:" + query);
String result = this.calculate.calculate(query);
if (result.isEmpty()) {
respPacket.setExecutType(Integer.MIN_VALUE);
respPacket.setData(getBytes("Expression error."));
}else{
respPacket.setData(getBytes(result));
} } catch (Exception e) {
respPacket.setExecutType(Integer.MIN_VALUE);
respPacket.setData(getBytes(e.getMessage()));
}
return respPacket;
} else {
return InternetPacket.getUnknowPacket();
}
} /**
* Convert string to byte[].
*
* @param content
* @return
*/
private byte[] getBytes(String content) {
byte[] bytes;
try {
bytes = content.getBytes("UTF-8");
} catch (UnsupportedEncodingException ex) {
bytes = content.getBytes();
}
return bytes;
} /**
* Convert byte[] to string.
*
* @param bytes
* @return
*/
private String getString(byte[] bytes) {
try {
return new String(bytes, "UTF-8").trim();
} catch (UnsupportedEncodingException ex) {
return new String(bytes).trim();
}
}
}

这里面有几个注意的事项:

1. 一定要继承 ICallback。

2. packet.getExecutType() == 2 表示它的执行类型,需要在plugin.json 中配置。

第五步:启动插件服务。

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.iveely.plugins.calculator; import com.iveely.framework.net.Server; /**
*
* @author 凡平
*/
public class Program { /**
* @param args the command line arguments
*/
public static void main(String[] args) {
int port = 5002;
System.out.println("Server started, port = " + port);
EventHandler handler = new EventHandler();
Server server = new Server(handler, port);
server.start();
} }

按照上面,五个步骤,你就完成了一个最基本的插件编写,生成jar包,找一台机器,将它运行起来,要让搜索引擎能够正常使用,还需要让搜索引擎知道这个插件,那么需要配置plugin.json文件。

如何编写Iveely搜索引擎插件的更多相关文章

  1. 自己编写Android Studio插件 别停留在用的程度了(转载)

    转自:自己编写Android Studio插件 别停留在用的程度了 1概述 相信大家在使用Android Studio的时候,或多或少的会使用一些插件,适当的配合插件可以帮助我们提升一定的开发效率,更 ...

  2. 用jquery编写的分页插件

    用jquery编写的分页插件 源码 function _pager_go(total_page) { var page_str = $("#_pager_textbox").val ...

  3. 用jquery编写的tab插件

    用jquery编写的tab插件 源码 $.fn.ss_tab = function (options) { var box = $(this); var btns = $(this).find(&qu ...

  4. 如何自己编写一个easyui插件续

    接着如何自己编写一个easyui插件继续分享一下如何从上一节写的“hello”插件继承出一个“hello2”. 参考了combobox的源码中继承combo,当然我这个简单很多了.都是根据自己的理解来 ...

  5. 用Javascript编写Chrome浏览器插件

    原文:http://homepage.yesky.com/62/11206062.shtml 用Javascript编写Chrome浏览器插件 2010-04-12 07:30 来源:天极网软件频道 ...

  6. 如何编写一个gulp插件

    很久以前,我们在"细说gulp"随笔中,以压缩JavaScript为例,详细地讲解了如何利用gulp来完成前端自动化. 再来短暂回顾下,当时除了借助gulp之外,我们还利用了第三方 ...

  7. 使用canvas编写时间轴插件

    使用canvas编写时间轴插件 背景 项目中有一个视频广场的功能,需要一个时间轴类似视频播放中进度条功能一样显示录像情况,并且可以点击.拖动.放大缩小展示时间轴,获取到时间轴的某个时间.原来的时间轴是 ...

  8. JQuery编写自己的插件(七)

    一:jQuery插件的编写基础1.插件的种类编写插件的目的是给一系列已经方法或函数做一个封装,以便在其他地方重复使用,方便后期维护和提高开发效率.常见的种类有以下三种:封装对象方法的插件

  9. 从零开始编写一个vue插件

    title: 从零开始编写一个vue插件 toc: true date: 2018-12-17 10:54:29 categories: Web tags: vue mathjax 写毕设的时候需要一 ...

随机推荐

  1. PL/SQL之--流程控制语句

    一.简介 像编程语言一样,oracle PL/SQL也有自己的流程控制语句.通过流程控制语句,我们可以在PL/SQL中实现一下比较复杂的业务逻辑操作.而无需到程序中去控制,在一定程度上提高了效率,这也 ...

  2. Hive DDL DML SQL操作

    工作中经常要用到的一些东西,一直没整理,用的多的记住了,用的不多的每次都是去查,所以记录一下. DDL(数据定义语言),那就包括建表,修改表结构等等了 建表:create hive table hiv ...

  3. linux—【用户和组的管理操作】(5)

    用户:user 组:group 增加:add 修改:modify   mod 删除:delete    del useradd     增加用户 usermod    修改用户 userdel     ...

  4. linux下对2个连通的串口读写遇到的问题

    想要分析下zmodem协议,搜索发现linux下的工具lrzsz是一个包含x,y,z modem传输的工具,下载其源码,下载.它可以借助各种串行的接口进行数据传输,比如串口,socket也可以,这点描 ...

  5. solr性能调优

    Schema Design Considerations indexed fields indexed fields 的数量将会影响以下的一些性能: 索引时的时候的内存使用量 索引段的合并时间 优化时 ...

  6. 算法实践——Twitter算法面试题(积水问题)的线性时间解法

    问题描述:在下图里我们有不同高度的挡板.这个图片由一个整数数组所代表,数组中每个数是墙的高度.下图可以表示为数组(2.5.1.2.3.4.7.2).假如开始下雨了,那么挡板之间的水坑能够装多少水(水足 ...

  7. 【软件使用】Windows下的Objective-C集成开发环境搭建(IDE)

    Objective-C是苹果软件的编程语言,想要上机学习.调试,有一个集成开发环境(IDE)方便很多.有三类方法搭建Objective-C的集成开发环境: 1)   使用苹果的平台,集成开发环境使用X ...

  8. ASP.NET URL伪静态重写实现方法

    ASP.NET URL伪静态重写实现方法 首先说下,ASP.NET URL伪静态只是将~/a_1.html指向到了~/a.aspx?ID=1,但a.aspx还是真实存在的,你不用./a_1.html来 ...

  9. HDU 2487 Ugly Windows

    递归求解,代码不太好看,是2013年7月写的 代码: #include<stdio.h> #include<iostream> #include<string.h> ...

  10. SVN和git的使用(附github的简单玩法)

    今天简单的总结了下SVN和git的使用,也尝试了下github,应该好好提高下自己的英文水平了,梦想有一天不再使用任何翻译软件. [svn]:集中式的代码管理工具(版本控制工具--版本记录) 1> ...