85.6. pet Store 示例决策(genda 组、全局变量、回调和 GUI 集成)


Pet Store 示例决定集演示了如何在规则中使用电缆组和全局变量,以及如何将 Red Hat Process Automation Manager 规则与图形用户界面(GUI)集成。在这种情况下,基于 Swing 的桌面应用程序。这个示例还演示了如何使用回调与正在运行的决策引擎交互,根据运行时工作内存的更改更新 GUI。

以下是 Pet Store 示例的概述:

  • 名称 :petstore
  • 主类org.drools.examples.petstore.PetStoreExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.petstore.PetStore.drl (在 src/main/resources中)
  • 目标 :演示规则关联组、全局变量、回调和 GUI 集成

在 Pet Store 示例中,P etStoreExample.java 类定义了以下主体类(除了处理 Swing 事件的多个类外):

  • Petstore 包含 main () 方法。
  • PetStoreUI 负责创建和显示基于 Swing 的 GUI。此类包含几个较小的类,主要用于响应各种 GUI 事件,如用户鼠标点击。
  • TableModel 包含表数据。此类基本上是一个 JavaBean,它扩展了 Swing 类 AbstractTableModel
  • 签出回调 可让 GUI 与规则交互。
  • Ordershow 保留您要购买的项目。
  • 购买 存储您购买的订购和产品的详细信息。
  • 产品 是一种 JavaBean,其中包含可用于购买的产品及其价格。

本例中的许多 Java 代码是基于普通 JavaBean 或 Swing 的普通代码。有关 Swing 组件的更多信息,请参阅有关 使用 JFC/Swing 创建 GUI 的 Java 指南。

Pet Store 示例中的规则执行行为

与其他示例决定,事实被立即触发,Petet Store 示例不会执行规则,直到基于用户交互收集更多事实。示例通过由构造器创建的 PetStoreUI 对象执行规则,该对象接受用于收集产品的 Vector 对象。然后,示例使用 CheckoutCallback 类的实例,其中包含之前载入的规则基础。

pet Store KIE 容器和事实执行设置

// KieServices is the factory for all KIE services.
KieServices ks = KieServices.Factory.get();

// Create a KIE container on the class path.
KieContainer kc = ks.getKieClasspathContainer();

// Create the stock.
Vector<Product> stock = new Vector<Product>();
stock.add( new Product( "Gold Fish", 5 ) );
stock.add( new Product( "Fish Tank", 25 ) );
stock.add( new Product( "Fish Food", 2 ) );

// A callback is responsible for populating the working memory and for firing all rules.
PetStoreUI ui = new PetStoreUI( stock,
                                new CheckoutCallback( kc ) );
ui.createAndShowGUI();
Copy to Clipboard Toggle word wrap

触发规则的 Java 代码位于 CheckoutCallBack.checkout () 方法中。当用户在 UI 中点 Checkout 时触发此方法。

从 CheckoutCallBack.checkout ()执行规则

public String checkout(JFrame frame, List<Product> items) {
    Order order = new Order();

    // Iterate through list and add to cart.
    for ( Product p: items ) {
        order.addItem( new Purchase( order, p ) );
    }

    // Add the JFrame to the ApplicationData to allow for user interaction.

    // From the KIE container, a KIE session is created based on
    // its definition and configuration in the META-INF/kmodule.xml file.
    KieSession ksession = kcontainer.newKieSession("PetStoreKS");

    ksession.setGlobal( "frame", frame );
    ksession.setGlobal( "textArea", this.output );

    ksession.insert( new Product( "Gold Fish", 5 ) );
    ksession.insert( new Product( "Fish Tank", 25 ) );
    ksession.insert( new Product( "Fish Food", 2 ) );

    ksession.insert( new Product( "Fish Food Sample", 0 ) );

    ksession.insert( order );

    // Execute rules.
    ksession.fireAllRules();

    // Return the state of the cart
    return order.toString();
}
Copy to Clipboard Toggle word wrap

示例代码将两个元素传递给 CheckoutCallBack.checkout () 方法。一个元素是 JFrame Swing 组件的处理,它包括输出文本帧,位于 GUI 的底部。第二个元素是订购项的列表,它来自 TableModel,它将信息从 GUI 右上角的 Table 区域存储。

for 循环将来自 GUI 的订购项列表转换为 Order JavaBean,也包含在 PetStoreExample.java 文件中。

在这种情况下,规则在无状态 KIE 会话中触发,因为所有数据都存储在 Swing 组件中,且不会执行,直到用户在 UI 中点 Checkout。每次点击 Checkout 时,列表的内容都会从 Swing TableModel 移到 KIE 会话工作内存中,然后使用 ksession.fireAllRules () 方法执行。

在此代码中,对 KieSession 有 9 个调用。首先从 KieContainer 创建一个新的 KieSession (此 KieContainer 中从 main () 方法中的 CheckoutCallBack 类传递的示例)。接下来的两个调用传递在规则中保存全局变量的两个对象:Swing 文本区域和用于编写消息的 Swing 帧。更多插入将产品的信息放在 KieSession 中,以及订购列表中。最后的调用是标准 fireAllRules ()

pet Store 规则文件导入、全局变量和 Java 功能

PetStore.drl 文件包含标准软件包和导入语句,供规则提供各种 Java 类。规则文件还包含 要在规则中使用的全局变量,定义为 和文本。全局变量包含对之前被名为 setGlobal () 方法的 Java 代码传递的 Swing 组件 JFrameJTextArea 组件的引用。与规则中的标准变量不同,当规则触发后马上过期,全局变量会在 KIE 会话生命周期中保留其值。这意味着这些全局变量的内容可用于评估所有后续规则。

Petstore.drl 软件包、导入和全局变量

package org.drools.examples;

import org.kie.api.runtime.KieRuntime;
import org.drools.examples.petstore.PetStoreExample.Order;
import org.drools.examples.petstore.PetStoreExample.Purchase;
import org.drools.examples.petstore.PetStoreExample.Product;
import java.util.ArrayList;
import javax.swing.JOptionPane;

import javax.swing.JFrame;

global JFrame frame
global javax.swing.JTextArea textArea
Copy to Clipboard Toggle word wrap

PetStore.drl 文件还包含文件中规则使用的两个功能:

PetStore.drl Java functions

function void doCheckout(JFrame frame, KieRuntime krt) {
        Object[] options = {"Yes",
                            "No"};

        int n = JOptionPane.showOptionDialog(frame,
                                             "Would you like to checkout?",
                                             "",
                                             JOptionPane.YES_NO_OPTION,
                                             JOptionPane.QUESTION_MESSAGE,
                                             null,
                                             options,
                                             options[0]);

       if (n == 0) {
            krt.getAgenda().getAgendaGroup( "checkout" ).setFocus();
       }
}

function boolean requireTank(JFrame frame, KieRuntime krt, Order order, Product fishTank, int total) {
        Object[] options = {"Yes",
                            "No"};

        int n = JOptionPane.showOptionDialog(frame,
                                             "Would you like to buy a tank for your " + total + " fish?",
                                             "Purchase Suggestion",
                                             JOptionPane.YES_NO_OPTION,
                                             JOptionPane.QUESTION_MESSAGE,
                                             null,
                                             options,
                                             options[0]);

       System.out.print( "SUGGESTION: Would you like to buy a tank for your "
                           + total + " fish? - " );

       if (n == 0) {
             Purchase purchase = new Purchase( order, fishTank );
             krt.insert( purchase );
             order.addItem( purchase );
             System.out.println( "Yes" );
       } else {
            System.out.println( "No" );
       }
       return true;
}
Copy to Clipboard Toggle word wrap

这两个功能执行以下操作:

  • doCheckout () 显示一个对话框,该对话框询问用户是否是她或他希望签出的。如果用户这样做,则重点设置为 checkout sales 组,使该组中的规则能够触发。
  • requireTank () 显示一个对话框,它要求用户在她或他希望购买 fish tank 时询问用户。如果用户这样做,会将一个新的 fish tank 产品 添加到工作内存的顺序列表中。
注意

在本例中,所有规则和功能都在同一个规则文件中有效。在生产环境中,您通常会在不同的文件中分隔规则和功能,或构建静态 Java 方法并使用导入功能导入文件,如 导入功能 my.package.name.hello

带有销售组的 pet 存储规则

Pet Store 示例中的大多数规则都使用电缆组来控制规则执行。通过电缆组,您可以对决策引擎人员进行分区,以提供更多对规则组的执行控制。默认情况下,所有规则都位于 products 组 MAIN 中。您可以使用 sales -group 属性为规则指定不同的 sales 组。

最初,工作内存将其重点放在电缆组 MAIN 上。只有组收到重点时,才会触发电缆组中的规则。您可以使用 setFocus () 或 rule 属性 auto-focus 设置重点。auto-focus 属性可让规则在匹配并激活规则时自动为其电缆组赋予一个重点。

Pet Store 示例对规则使用以下电缆组:

  • "init"
  • "evaluate"
  • "show items"
  • "checkout"

例如,示例规则 "Explode Cart" 使用 "init" cart 组来确保它有选择触发并插入 KIE 会话工作内存中:

规则"Explode Cart"

// Insert each item in the shopping cart into the working memory.
rule "Explode Cart"
    agenda-group "init"
    auto-focus true
    salience 10
  when
    $order : Order( grossTotal == -1 )
    $item : Purchase() from $order.items
  then
    insert( $item );
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "show items" ).setFocus();
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "evaluate" ).setFocus();
end
Copy to Clipboard Toggle word wrap

此规则与尚未计算其 grossTotal 的所有顺序匹配。每个购买项目的执行循环(按该顺序排列)。

规则使用与 leader 组相关的以下功能:

  • runlevel-group "init" 定义 products 组的名称。在这种情况下,只有一个规则位于组中。但是,Java 代码和规则结果都不适用于此组,因此它依赖于 auto-focus 属性来触发它。
  • auto-focus true 确保此规则虽然是 sales 组中的唯一规则,则在从 Java 代码调用 fireAllRules () 时获得触发的机会。
  • kcontext…​.setFocus () 将重点设置为 "显示项目 " 和"评估" 组,允许触发规则。在实践中,您将按顺序执行所有项目,将它们插入到内存中,然后在插入后触发其他规则。

"show items" products group 仅包含一条规则,"Show items"。对于 KIE 会话工作内存中当前顺序的每个购买,规则会根据规则文件中定义的 textArea 变量将详细信息记录到 GUI 底部的文本区域。

规则"Show items"

rule "Show Items"
    agenda-group "show items"
  when
    $order : Order()
    $p : Purchase( order == $order )
  then
   textArea.append( $p.product + "\n");
end
Copy to Clipboard Toggle word wrap

"评估" 公司组也从 "Explode Cart" 规则中获得了重点。此电话号码组包含两个规则 :"Free Fish Food Sample""Suggest Tank",它们按顺序执行。

规则 "Free Fish Food Sample"

// Free fish food sample when users buy a goldfish if they did not already buy
// fish food and do not already have a fish food sample.
rule "Free Fish Food Sample"
    agenda-group "evaluate" 
1

  when
    $order : Order()
    not ( $p : Product( name == "Fish Food") && Purchase( product == $p ) ) 
2

    not ( $p : Product( name == "Fish Food Sample") && Purchase( product == $p ) ) 
3

    exists ( $p : Product( name == "Gold Fish") && Purchase( product == $p ) ) 
4

    $fishFoodSample : Product( name == "Fish Food Sample" );
  then
    System.out.println( "Adding free Fish Food Sample to cart" );
    purchase = new Purchase($order, $fishFoodSample);
    insert( purchase );
    $order.addItem( purchase );
end
Copy to Clipboard Toggle word wrap

只有在满足以下条件时,规则 "Free Fish Food Sample" 才会触发:

1
在规则执行中,评估组 "evaluate" 组。
2
用户还没有 fish food。
3
用户还没有免费的 fish food 示例。
4
用户按顺序有一个黄金的fish。

如果顺序事实满足所有这些要求,则会创建一个新产品(Fish Food Sample),并添加到工作内存的顺序中。

规则"Suggest Tank"

// Suggest a fish tank if users buy more than five goldfish and
// do not already have a tank.
rule "Suggest Tank"
    agenda-group "evaluate"
  when
    $order : Order()
    not ( $p : Product( name == "Fish Tank") && Purchase( product == $p ) ) 
1

    ArrayList( $total : size > 5 ) from collect( Purchase( product.name == "Gold Fish" ) ) 
2

    $fishTank : Product( name == "Fish Tank" )
  then
    requireTank(frame, kcontext.getKieRuntime(), $order, $fishTank, $total);
end
Copy to Clipboard Toggle word wrap

只有在满足以下条件时,规则 "Suggest Tank" 才会触发:

1
用户的顺序没有 fish tank。
2
用户按顺序有超过五个 fish。

当规则触发时,它将调用规则文件中定义的 requireTank () 函数。此函数会显示一个对话框,它要求用户在她或他希望购买 fish tank 时询问用户。如果用户这样做,会将一个新的 fish tank 产品 添加到工作内存的顺序列表中。当规则调用 requireTank () 函数时,该规则会传递 全局变量,以便函数能够处理 Swing GUI。

Pet Store 示例中的 "do checkout" 规则没有 sales 组,且没有 when 条件,因此始终执行该规则并被视为默认 MAIN phone 组的一部分。

规则"do checkout"

rule "do checkout"
  when
  then
    doCheckout(frame, kcontext.getKieRuntime());
end
Copy to Clipboard Toggle word wrap

当规则触发时,它将调用规则文件中定义的 doCheckout () 函数。此函数会显示一个对话框,用于询问用户是否是她或他希望签出的对话框。如果用户这样做,则重点设置为 checkout sales 组,使该组中的规则能够触发。当规则调用 doCheckout () 函数时,该规则会传递 全局变量,以便函数能够处理 Swing GUI。

注意

本例还演示了一个故障排除技术,如果结果没有如您预期执行:您可以从规则的 when 语句中删除条件,并在 then 语句中测试操作以验证操作是否已正确执行。

"checkout" products 组包含三个规则,用于处理顺序签出并应用任何活动:" Gross Total", " Apply 5% Discount", 和 "Apply 10% Discount"

规则 "Gross Total", "Apply 5% Discount", 和 "Apply 10% Discount"

rule "Gross Total"
    agenda-group "checkout"
  when
    $order : Order( grossTotal == -1)
    Number( total : doubleValue ) from accumulate( Purchase( $price : product.price ),
                                                              sum( $price ) )
  then
    modify( $order ) { grossTotal = total }
    textArea.append( "\ngross total=" + total + "\n" );
end

rule "Apply 5% Discount"
    agenda-group "checkout"
  when
    $order : Order( grossTotal >= 10 && < 20 )
  then
    $order.discountedTotal = $order.grossTotal * 0.95;
    textArea.append( "discountedTotal total=" + $order.discountedTotal + "\n" );
end

rule "Apply 10% Discount"
    agenda-group "checkout"
  when
    $order : Order( grossTotal >= 20 )
  then
    $order.discountedTotal = $order.grossTotal * 0.90;
    textArea.append( "discountedTotal total=" + $order.discountedTotal + "\n" );
end
Copy to Clipboard Toggle word wrap

如果用户还没有计算 gross 总计,则 Gross Total 将产品价格聚合到总计,请将这个总数放在 KIE 会话中,并使用 textArea 全局变量通过 Swing JTextArea 显示它。

如果 gross 总数介于 1020 之间(策展单位),"Apply 5% Discount" 规则计算活动总数,将其添加到 KIE 会话中,并在文本区域中显示它。

如果 gross 总数不小于 20"Apply 10% Discount" 规则会计算参与总数,将其添加到 KIE 会话中,并在文本区域中显示它。

pet Store 示例执行

与其他 Red Hat Process Automation Manager 决策示例类似,您可以通过在 IDE 中作为 Java 应用程序运行 org.drools.examples.petstore.PetStoreExample 类来执行 Pet Store 示例。

当您执行 Pet Store 示例时,会出现 Pet Store Demo GUI 窗口。此窗口显示可用产品列表(左下),这是所选产品的空列表(右下)、checkout 和 Reset 按钮(中间)和空系统消息区域(bottom)。

图 85.14. 启动后,pet Store 示例 GUI

本例中发生以下事件来建立此执行行为:

  1. main () 方法已运行并加载规则基础,但还没有触发规则。目前,这是与已运行的规则连接的唯一代码。
  2. 创建了一个新的 PetStoreUI 对象,并授予规则基础的处理,以便稍后使用。
  3. 各种 Swing 组件已执行其功能,并显示初始 UI 屏幕并等待用户输入。

您可以点击列表中的各种产品来浏览 UI 设置:

图 85.15. 探索 Pet Store 示例 GUI

还没有触发规则代码。UI 使用 Swing 代码来检测用户鼠标点击,并将所选产品添加到 TableModel 对象中,以便在 UI 右上角显示。本例演示了 Model-View-Controller 设计模式。

当您点 Checkout 时,规则将以以下方式触发:

  1. 方法 CheckOutCallBack.checkout () 被 Swing 类调用(eventually),等待用户单击 Checkout。这会将来自 TableModel 对象(每个 UI 右上角)的数据插入到 KIE 会话工作内存中。然后,方法会触发规则。
  2. "Explode Cart" 规则是第一个触发,auto-focus 属性设置为 true。规则循环到 cart 中的所有产品,确保产品处于工作内存中,然后为 "显示项"和" 评估" 组提供触发的选项。这些组中的规则将 cart 的内容添加到文本区域( UI 不存在),评估您是否有资格免费 fish food,并决定是否希望购买 fish tank。

    图 85.16. fish tank mailbox

  3. "do checkout" 规则是触发的下一个规则,因为目前没有其他电缆组,因为它是默认的 MAIN farm 组的一部分。此规则始终调用 doCheckout () 函数,它要求您签出。
  4. doCheckout () 函数将重点设置为 "checkout" 电缆组,为该组中的规则提供要触发的选项。
  5. "checkout" 电缆组中的规则显示 cart 的内容,并应用适当的语音。
  6. 然后,Swing 会等待用户输入来选择更多产品(并导致规则再次触发)或关闭 UI。

    图 85.17. 所有规则触发后的 pet Store 示例 GUI

您可以添加更多 System.out 调用来在 IDE 控制台中演示此事件流:

IDE 控制台中的 system.out 输出

Adding free Fish Food Sample to cart
SUGGESTION: Would you like to buy a tank for your 6 fish? - Yes
Copy to Clipboard Toggle word wrap

返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat