37、Jess在J2EE环境中的应用与函数详解

Jess在J2EE环境中的应用与函数详解

1. 基于RMI的Jess规则服务器搭建

1.1 远程接口定义

在J2EE环境中使用Jess时,我们需要创建远程版本的 jess.Rete 以及一个工厂类来创建远程 Rete 实例。远程接口需要扩展 java.rmi.Remote ,并且其所有方法必须声明抛出 java.rmi.RemoteException 。参数和返回值类型必须是可序列化的,或者本身就是远程接口。

以下是工厂类的远程接口定义:

import java.rmi.*;
interface JessFactory extends Remote {
    Jess create() throws RemoteException;
}

Jess 是远程 Rete 接口的名称,其定义如下:

import java.rmi.*;
import jess.*;
interface Jess extends Remote {
    Value executeCommand(String command)
        throws RemoteException, JessException;
    void store(String name, Object object) throws RemoteException;
    Value fetch(String name) throws RemoteException;
}

1.2 接口实现

1.2.1 JessFactory接口实现
import jess.*;
import java.rmi.*;
import java.rmi.server.*;

public class JessFactoryImpl extends UnicastRemoteObject
    implements JessFactory {
    private JessFactoryImpl() throws RemoteException {
    }
    public Jess create() throws RemoteException {
        return new JessImpl();
    }
}

通过扩展 UnicastRemoteObject ,远程对象实现类可以自动导出自身或连接到网络。

1.2.2 Jess接口实现
import java.rmi.*;
import java.rmi.server.*;
import jess.*;
public class JessImpl extends UnicastRemoteObject
    implements Jess {
    private Rete m_rete = new Rete();
    JessImpl() throws RemoteException {}
    public Value executeCommand(String command)
        throws JessException {
        return m_rete.executeCommand(command);
    }
    public void store(String name, Object object) {
        m_rete.store(name, object);
    }
    public Value fetch(String name) {
        return m_rete.fetch(name);
    }
}

每个 JessImpl 实例包含一个 jess.Rete 实例,因此 JessImpl 对象是独立的。

1.3 主方法实现

编写RMI服务器时,需要提供一个主方法来创建服务器启动时应存在的对象,并将这些对象注册到命名服务中,以便客户端可以找到它们。这里使用 rmiregistry 作为命名服务,通过 java.rmi.Naming 类进行访问。

public static void main(String[] argv) throws Exception {
    JessFactoryImpl impl = new JessFactoryImpl();
    Naming.rebind("Jess", impl);
    System.out.println("Jess server running");
}

1.4 生成存根

使用 rmic 存根编译器对编译后的实现类进行操作:

rmic JessImpl JessFactoryImpl

该命令将创建 JessImpl_Stub.class JessImpl_Skel.class 以及 JessFactoryImpl 的存根和骨架类。

1.5 示例客户端

以下是一个简单的客户端应用程序,它根据命令行参数构建Jess命令,并在远程Jess对象中执行该命令:

import java.rmi.*;
public class JessClient {
    public static void main(String[] argv)
        throws Exception {
        JessFactory factory = (JessFactory) Naming.lookup("Jess");
        Jess jess = factory.create();
        StringBuffer sb = new StringBuffer();
        for (int i=0; i<argv.length; ++i) {
            sb.append(argv[i]);
            sb.append(" ");
        }
        System.out.println(jess.executeCommand(sb.toString()));
    }
}

编译该客户端需要两个远程接口类,运行时还需要两个存根类文件。

1.6 最终优化

RMI包含一种使用Web服务器作为类服务器远程加载存根类文件(和其他类)的机制。要启用此机制,需要安装特殊的RMI安全管理器,定义安全策略,并设置几个系统属性来定义类服务器的位置。

2. JSR 94: javax.rules API

2.1 javax.rules API概述

javax.rules 包是一个标准的轻量级API,用于连接和使用规则引擎,可用于J2SE和J2EE应用程序。它包括存储和管理规则库的机制以及表示与规则引擎的各个会话的类。使用该API可以以通用方式编写Java代码来处理规则引擎,从而在切换规则引擎供应商时无需更改代码。

2.2 使用javax.rules API

2.2.1 环境设置

在J2EE环境中,可以使用JNDI检索 RuleServiceProvider ;否则,可以从 javax.rules.RuleServiceProviderManager 类获取:

String implName = "org.jcp.jsr94.ri.RuleServiceProvider"; 
Class.forName(implName);
RuleServiceProvider serviceProvider =
    RuleServiceProviderManager.getRuleServiceProvider(implName);

获取 RuleServiceProvider 后,可以检索 RuleAdministrator ,进而获取 RuleExecutionSetProvider 来创建 RuleExecutionSet

以下是从本地文件 rules.xml 创建 RuleExecutionSet 的示例:

RuleAdministrator admin = serviceProvider.getRuleAdministrator();
HashMap properties = new HashMap();
properties.put("name", "My Rules");
properties.put("description", "A trivial rulebase");
FileReader reader = new FileReader("rules.xml");
RuleExecutionSet ruleSet = null;
try {
    LocalRuleExecutionSetProvider lresp =
        admin.getLocalRuleExecutionSetProvider(properties);
    ruleSet = lresp.createRuleExecutionSet(reader, properties);
} finally {
    reader.close();
}
admin.registerRuleExecutionSet("rules", ruleSet, properties);
2.2.2 规则引擎执行

在运行时阶段,创建 RuleSession 。有两种类型的 RuleSession :有状态和无状态。有状态的 RuleSession 的工作内存会在方法调用之间持久化,而无状态的 RuleSession 是一次性的。

以下是创建有状态 RuleSession 、添加对象、执行规则并检索工作内存内容的示例:

RuleRuntime runtime = rsp.getRuleRuntime();
StatefulRuleSession session = (StatefulRuleSession)
    runtime.createRuleSession("rules", properties,
    RuleRuntime.STATEFUL_SESSION_TYPE);
session.addObject(new Integer(1));
session.addObject("A string");
session.executeRules();
List results = session.getObjects();
session.release();

2.3 参考实现

javax.rules 的第一个实现是参考实现(RI),它是Jess的包装器。工作内存元素是任意Java对象,每次将对象添加到工作内存时,Jess会自动为其定义一个 defclass

以下是一个添加两个整数的规则示例:

(defclass java.lang.Integer java.lang.Integer nil)
(defrule add-two-integers
    (java.lang.Integer (OBJECT ?i1))
    (java.lang.Integer (OBJECT ?i2&~?i1))
    =>
    (undefinstance ?i1)
    (undefinstance ?i2)
    (bind ?i3 (new Integer (+ (?i1 intValue) (?i2 intValue))))
    (definstance java.lang.Integer ?i3 static))

RI的输入文件必须是XML格式,以下是包含上述规则的XML文件示例:

<?xml version="1.0" encoding="UTF-8"?>
<rule-execution-set>
    <name>Mathemetical rules</name>
    <description>One rule that adds two Integers</description>
    <code>
        (defclass java.lang.Integer java.lang.Integer nil)
        (defrule add-two-integers
            (java.lang.Integer (OBJECT ?i1))
            (java.lang.Integer (OBJECT ?i2&amp;~?i1))
            =&gt;
            (undefinstance ?i1)
            (undefinstance ?i2)
            (bind ?i3 (new Integer (+ (?i1 intValue) (?i2 intValue))))
            (definstance java.lang.Integer ?i3 static))
    </code>
</rule-execution-set>

2.4 总结

通过使用Jess和Java RMI可以构建自定义规则服务器,并且可以根据需要进行定制。 javax.rules API为从多个供应商的规则引擎提供了可移植的通用访问方式,在J2EE环境中管理规则库具有强大的功能,同时在运行时组件中使用也相对简单。

3. Jess函数列表

Jess 6.1包含了众多函数,以下是部分函数的介绍:
| 函数 | 描述 |
| — | — |
| (- <number> <number>+) | 返回第一个参数减去所有后续参数的结果,若参数中有浮点数则返回浮点数,否则返回整数 |
| (/ <number> <number>+) | 返回第一个参数除以所有后续参数的结果,返回值为浮点数 |
| (* <number> <number>+) | 返回参数的乘积,若参数中有浮点数则返回浮点数,否则返回整数 |
| (+ <number> <number>+) | 返回参数的和,若参数中有浮点数则返回浮点数,否则返回整数 |
| (abs <number>) | 返回参数的绝对值 |
| (agenda [<module name>]) | 显示规则激活列表,可指定模块名或使用 * 显示所有激活 |
| (and <expression>+) | 若所有参数都不评估为 FALSE ,则返回 TRUE ,否则返回 FALSE |
| (apply <expression>+) | 将第一个参数作为Jess函数调用,对其余参数进行操作 |

3.1 函数使用注意事项

  • 大多数函数对参数的接受比较灵活,多余的参数通常会被忽略,某些情况下缺少的参数会使用默认值。
  • 文件名参数需要遵循Jess的有效符号或字符串规则,在Win32系统中,路径名应使用双反斜杠 \\ 或正斜杠 / 作为目录分隔符,包含冒号 : 或空格的路径名必须用双引号括起来。
  • 一些“函数”实际上是Jess语言内置的构造,不能像普通函数一样调用,如 defrule deftemplate 等。

3.2 函数调用示例

Jess> (bind ?function (read))
+ ;; 输入 "+"
"+"
Jess> (apply ?function 1 2 3 4 5)
15

3.3 流程图:Jess函数调用流程

graph TD;
    A[输入函数及参数] --> B{参数检查};
    B -- 参数合法 --> C[执行函数操作];
    B -- 参数不合法 --> D[抛出JessException];
    C --> E[返回结果];

Jess函数提供了丰富的功能,可以满足各种规则编程的需求。在使用时,需要根据函数的参数要求和功能特点进行合理调用。通过掌握这些函数,可以更高效地使用Jess进行规则开发。

4. 更多Jess函数介绍

4.1 逻辑与条件函数

函数 描述
(or <expression>+) 若任何参数评估为非 FALSE 值,则返回 TRUE ,否则返回 FALSE
(not <expression>) 若唯一参数评估为 FALSE ,则返回 TRUE ,否则返回 FALSE
(if <boolean> then <expression>+ [else <expression>+]) 根据布尔表达式的值,有条件地执行一组操作
4.1.1 逻辑函数示例
Jess> (or TRUE FALSE)
TRUE
Jess> (not FALSE)
TRUE
Jess> (if (eq 1 1) then (printout t "Equal") else (printout t "Not equal"))
Equal

4.2 列表操作函数

函数 描述
(create$ <expression>*) 创建一个包含所有给定参数的新列表
(first$ <list>) 返回列表的第一个元素
(rest$ <list>) 返回列表除第一个元素外的其余元素
(length$ <list>) 返回列表的长度
4.2.2 列表操作示例
Jess> (create$ 1 2 3)
(1 2 3)
Jess> (first$ (create$ 1 2 3))
1
Jess> (rest$ (create$ 1 2 3))
(2 3)
Jess> (length$ (create$ 1 2 3))
3

4.3 文件与I/O函数

函数 描述
(open <lexeme> <lexeme> [r | w | a]) 打开一个文件,可指定读写模式
(close [<lexeme>+]) 关闭指定的I/O路由器
(printout <lexeme> <expression>+) 将参数打印到指定的路由器
(read [<lemexe>]) 从指定路由器读取一个符号、字符串或数字
(readline [<lexeme>]) 从指定I/O路由器读取一整行
4.3.1 文件与I/O操作示例
Jess> (open "test.txt" "output" "w")
Jess> (printout "output" "Hello, World!")
Jess> (close "output")
Jess> (open "test.txt" "input" "r")
Jess> (readline "input")
"Hello, World!"
Jess> (close "input")

4.4 流程图:Jess文件操作流程

graph TD;
    A[打开文件] --> B{文件是否打开成功};
    B -- 成功 --> C[执行读写操作];
    B -- 失败 --> D[输出错误信息];
    C --> E[关闭文件];

5. 规则引擎管理函数

5.1 规则清除与重置函数

函数 描述
(clear) 清除规则引擎,删除所有规则、事实等
(reset) 移除工作内存中的所有事实和议程中的所有激活,重新初始化规则引擎
5.1.1 规则管理示例
Jess> (assert (test-fact))
<Fact-0>
Jess> (reset)
Jess> (facts)
(initial-fact)

5.2 焦点管理函数

函数 描述
(focus <symbol>+) 更改焦点模块,影响下一个要触发的规则
(clear-focus-stack) 清除焦点栈中的所有模块
(get-focus) 返回当前焦点模块的名称
5.2.2 焦点管理示例
Jess> (focus module1)
Jess> (get-focus)
"module1"
Jess> (clear-focus-stack)
Jess> (get-focus)
nil

5.3 流程图:Jess规则引擎重置流程

graph TD;
    A[调用reset函数] --> B[移除工作内存中的事实];
    B --> C[移除议程中的激活];
    C --> D[断言初始事实和deffacts中的事实];
    D --> E[初始化defglobals(若设置允许)];

6. 高级Jess函数应用

6.1 动态规则定义

使用 build 函数可以在运行时动态定义规则。

Jess> (build "(defrule dynamic-rule (test-fact) => (printout t 'Dynamic rule fired'))")
Jess> (assert (test-fact))
<Fact-0>
Jess> (run)
Dynamic rule fired

6.2 跨引擎通信

使用 call-on-engine 函数可以在多个Rete引擎之间发送消息。

Jess> (bind ?engine (new jess.Rete))
<External-Address:jess.Rete>
Jess> (call-on-engine ?engine (+ 2 2))
4

6.3 自定义冲突解决策略

可以通过实现 jess.Strategy 接口并使用 set-strategy 函数来指定自定义的冲突解决策略。

// 自定义策略类
import jess.*;
import java.util.*;

public class CustomStrategy implements Strategy {
    public void init(Rete engine) {}
    public void add(Activation a, Rete engine) {}
    public Activation next(Rete engine) { return null; }
    public void remove(Activation a, Rete engine) {}
    public String getName() { return "custom-strategy"; }
}
Jess> (set-strategy custom-strategy)

7. 总结与展望

Jess提供了丰富的功能和灵活的编程方式,无论是在规则服务器的搭建、使用 javax.rules API进行规则管理,还是使用各种Jess函数进行规则编程,都能满足不同场景的需求。通过合理运用这些技术,可以开发出高效、智能的规则系统。

未来,随着技术的不断发展,Jess可能会进一步优化性能、扩展功能,为规则编程带来更多的可能性。同时,与其他技术的集成也将更加紧密,为开发者提供更强大的工具。在实际应用中,开发者可以根据具体需求,深入挖掘Jess的潜力,创造出更优秀的规则应用。

Jess的规则技术已经在多个领域得到了广泛应用,从简单的命令行应用到复杂的Web应用,都展示了其强大的能力。希望本文能为对Jess感兴趣的开发者提供有价值的参考,帮助他们更好地掌握和应用Jess技术。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值