KIE

版本 7.9.0

KIE 生态

图片.png

OptaPlanner 是一个本地搜索和优化的工具,独立于Drools Planner 。
UberFire 是新的workbench工程,提供类似Eclipse工作台功能。
KIE-WB 是整合了Guvnor 、drools、jbpm的uber工作台。jbpm-wb是虚的。

生命周期

  • Author 创作
    使用DRL、BPMN2、决策表、类进行知识创作
  • 构建
    将创作的知识构建为可部署的单元, JAR。
  • 测试
  • 部署
  • 使用 、管理

使用maven

使用maven构建, 遵循maven的实践规则。 KIE工程可以作为maven工程或module。 spring 中提供xml配置来代替元数据配置META-INF/kmodule.xml。

maven构建时不提供校验规则的机制, 可以通过插件实现 kie-maven-plugin 。

Kie项目具有普通maven的工程结构,唯一特点是需要包含一个kmodule.xml文件, 此文件必须放在Maven项目的resources / META-INF文件夹中,而所有其他Kie工件(如DRL或Excel文件)必须存储在resources文件夹或其下的任何其他子文件夹中。

由于工程使用默认的配置,因此最简单的kmodule.xml文件如下:



这种情况下,kmodule将包含一个默认的KieBase 。 所有存储在resources文件夹下及其子文件夹下的规则都将被编译进去。

创建KieContainer

从类路径下读取文件创建KieContainer ;

KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
图片.png

通过该方式,将所有的java 、kie资源都编译部署到KieContainer中,从而可以在运行时使用之。

kmodule.file

KieBase是所有应用程序知识定义的存储库。 它将包含规则,流程,函数和类型模型。 KieBase本身不包含数据;。

图片.png
图片.png

KieSession 存储和执行运行时数据。 它从KieBase创建或者当在kmodule.xml中定义时可以直接从KieContainer中创建。

如下实例, kmodule.xml中可以定义和配置多个KieBase,并且对于每个KieBase都可以创建不同的KieSession 。


  
    
  
  
    
    
  
  
    
      
      
        
      
      
        
        
        
        
      
    
  

kbase的属性设置:

Attribute name Default value Admitted values Meaning
name none any 从KieContainer中获取KieBase的name
includes none 逗号分隔列表 逗号分隔的列表,kmodule中定义的其他kbase都将包含在该中
packages all any comma separated list 该packages下所有的资源文件都将包含在该kbase中
default false true, false 定义该kbase是否是默认的,若是默认的则从KieContainer中可以不传name直接创建,最多只能有一个默认kbase
equalsBehavior identity identity, equality 定义当新fact插入working memory时drools的行为。 使用identity ,则总是创建一个新的FactHandle,除非同样的对象在workingmemory中不存在。 使用equality ,则只有心插入的对象不同于(根据其提供的equal方法比较)已经存在的fact才创建。
eventProcessingMode cloud cloud, stream 当以cloud模式创建时,事件被认为是一般的facts。 当stream时允许进行时间推理
declarativeAgenda disabled disabled, enabled 是否启用Declarative Agenda

Ksession的属性:

  • name , KIESession的唯一名称标识。用于从KieContainer中获取KieSession。
  • type , stateful、stateless, 默认是stateful ;
  • default , 默认false ;当默认true时, 则允许从KieContainer中不传入name获取。
  • clockType , realtime、pseudo, 默认realtime ; 定义事件时间戳是由系统时钟还是由应用程序控制的伪时钟确定的。 该时钟对于单元测试时间规则特别有用。
  • beliefSystem , simple, jtms, defeasible ; 默认simple ; 定义KieSession使用的信任系统的类型。

如前例所示, 可以在每个KieSession上声明一个日志记录器,一个或多个WorkItemHandlers,以及3中类型的监听器:ruleRuntimeEventListener, agendaEventListener and processEventListener 。

在kmodule.xml中声明之后, 既可以使用其name从KieContainer中检索KieBase 和 KieSession。

如:

KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();

KieBase kBase1 = kContainer.getKieBase("KBase1");
KieSession kieSession1 = kContainer.newKieSession("KSession2_1");
StatelessKieSession kieSession2 = kContainer.newStatelessKieSession("KSession2_2");

需要注意的是,由于KSession2_1和KSession2_2有两种不同的类型(第一种是有状态的,而第二种是无状态的),因此必须根据声明的类型在KieContainer上调用2种不同的方法。 如果向KieContainer请求的KieSession的类型与kmodule.xml文件中声明的类型不对应,则KieContainer将抛出RuntimeException。 此外,由于KieBase和KieSession已被标记为默认值,因此可以从KieContainer获取它们而不传递任何名称。

KieContainer kContainer = ...

KieBase kBase1 = kContainer.getKieBase(); // returns KBase1
KieSession kieSession1 = kContainer.newKieSession(); // returns KSession2_1

由于Kie项目也是Maven项目,因此在pom.xml文件中声明的groupId,artifactId和version用于生成在应用程序中唯一标识此项目的ReleaseId。 这允许通过简单地将其ReleaseId传递给KieServices从项目中创建新的KieContainer。

KieServices kieServices = KieServices.Factory.get();
ReleaseId releaseId = kieServices.newReleaseId( "org.acme", "myartifact", "1.0" );
KieContainer kieContainer = kieServices.newKieContainer( releaseId );

使用maven 构建

Maven的KIE插件可确保工件资源经过验证和预编译。 要使用该插件,只需将其添加到Maven pom.xml,然后packaging使用 kjar。

  kjar
  ...
  
    
      
        org.kie
        kie-maven-plugin
        7.9.0.Final
        true
      
    
  

该插件支持所有Drools / jBPM。 但是,如果您在Java类中使用特定的KIE注释,例如@ kie.api.Position,则需要将kie-api的编译时依赖项添加到项目中。 我们建议使用provided scope 添加KIE依赖项。 这样kjar尽可能保持轻量级,并且不依赖于任何特定的KIE版本。

在没有Maven插件的情况下构建KIE模块会将所有资源按原样复制到生成的JAR中。 当运行时加载JAR时,它将尝试构建所有资源。 如果存在编译问题,它将返回null KieContainer。 它还将编译开销推送到运行时。 通常不建议这样做,并且应始终使用Maven插件。

通过编程定义KieModule

支持通过编程的方式定义KieBase 和KieSession , 也支持通过编程将资源动态加载到项目中。 这需要使用KieFileSystem ,它是虚拟文件系统,可以通过它添加任意资源。

图片.png

可以通过KieServices获取KieFileSystem 。 kmodule.xml配置文件是必须的一步, kie提供了KieModuleModel来通过编程添加。

通过KieServices获取KieModuleModel ,配置其KieBases 和 KieSession , 转换为XML , 将XML添加到KieFileSysstem , 如下:

KieServices kieServices = KieServices.Factory.get();
KieModuleModel kieModuleModel = kieServices.newKieModuleModel();

KieBaseModel kieBaseModel1 = kieModuleModel.newKieBaseModel( "KBase1 ")
        .setDefault( true )
        .setEqualsBehavior( EqualityBehaviorOption.EQUALITY )
        .setEventProcessingMode( EventProcessingOption.STREAM );

KieSessionModel ksessionModel1 = kieBaseModel1.newKieSessionModel( "KSession1" )
        .setDefault( true )
        .setType( KieSessionModel.KieSessionType.STATEFUL )
        .setClockType( ClockTypeOption.get("realtime") );

KieFileSystem kfs = kieServices.newKieFileSystem();
kfs.writeKModuleXML(kieModuleModel.toXML());

向KieFileSystem添加其他组件:

KieFileSystem kfs = ...
kfs.write( "src/main/resources/KBase1/ruleSet1.drl", stringContainingAValidDRL )
        .write( "src/main/resources/dtable.xls",
                kieServices.getResources().newInputStreamResource( dtableFileStream ) );

上例显示可以将Kie工件添加为普通String 或 Resource 。 在后一种情况下,资源可以由KieResources工厂创建,也由KieServices提供。 KieResources提供了许多方便的工厂方法,可将InputStream,URL,File或表示文件系统路径的String转换为可由KieFileSystem管理的Resource。


图片.png

通常,可以从用于将其添加到KieFileSystem的名称的扩展名推断出资源的类型。 但是,也可以不遵循有关文件扩展名的Kie约定,并明确地将特定的ResourceType分配给资源,如下所示:

KieFileSystem kfs = ...
kfs.write( "src/main/resources/myDrl.txt",
           kieServices.getResources().newInputStreamResource( drlStream )
                      .setResourceType(ResourceType.DRL) );

向KieFileSystem中添加resource , 将KieFileSystem传给KieBuilder 来构建之。

图片.png

当KieFileSystem的内容被成功构建, 结果KieModule 被自动添加到KieRepository 。 KieRepository 是个单例,是所有KieModule的仓库。

图片.png

在此之后,可以通过KieServices使用其ReleaseId为该KieModule创建一个新的KieContainer。 但是,由于在这种情况下KieFileSystem不包含任何pom.xml文件(可以使用KieFileSystem.writePomXML方法添加一个),因此Kie无法确定KieModule的ReleaseId并为其分配默认值。 可以从KieRepository获取此默认ReleaseId,并用于标识KieRepository内部的KieModule。 以下示例显示了整个过程。

KieServices kieServices = KieServices.Factory.get();
KieFileSystem kfs = ...
kieServices.newKieBuilder( kfs ).buildAll();
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());

此时,可以从KieContainer中获取KieBases并创建新的KieSession,其方式与直接从类路径创建的KieContainer的方式完全相同。

检查编译结果是最佳做法。 KieBuilder报告了3种不同严重程度的编译结果:ERROR,WARNING和INFO。 ERROR表示项目的编译失败,没有生成KieModule,没有任何内容会添加到KieRepository。 警告和INFO结果可以忽略,但可供检查。

KieBuilder kieBuilder = kieServices.newKieBuilder( kfs ).buildAll();
assertEquals( 0, kieBuilder.getResults().getMessages( Message.Level.ERROR ).size() );

更改构建结果默认严重性

当添加一个同名的新规则时,默认会替换旧的规则,并打印出INFO结果。这在大多数时候是可以的,但有些情况不希望这么做,需要阻止规则更新并报告error。

可以通过API调用,系统属性或配置文件来完成。 从此版本开始,Drools支持规则更新和功能更新的可配置结果严重性。 要使用系统属性或配置文件对其进行配置,用户必须使用以下属性:

// sets the severity of rule updates
drools.kbuilder.severity.duplicateRule = 
// sets the severity of function updates
drools.kbuilder.severity.duplicateFunction = 

部署 Deploy

KieBase是所有知识的仓库,包括rule、process、function、type model。
KieBase本身不包含数据; KieBase可以从包括KieModule的KieContainer中获取。

图片.png

有时,如在OSGI环境, KieBase需要使用默认classloader加载不了的类型。 这种情况下,需要使用KieBaseConfiguration 来创建附加classloader 并传递KieContainer给他来创建KieBase。

KieServices kieServices = KieServices.Factory.get();
KieBaseConfiguration kbaseConf = kieServices.newKieBaseConfiguration( null, MyType.class.getClassLoader() );
KieBase kbase = kieContainer.newKieBase( kbaseConf );

KieBase创建并返回KieSession对象,它可以选择保留这些对象的引用。 当KieBase发生修改时,这些修改将应用于会话中的数据。 此引用是弱引用,它也是可选的,由布尔标志控制。

KieScanner

KieScanner允许连续监视Maven存储库,以检查是否已安装新版本的Kie项目。 在包装该项目的KieContainer中部署了一个新版本。 使用KieScanner需要kie-ci.jar在类路径上。


图片.png
KieServices kieServices = KieServices.Factory.get();
ReleaseId releaseId = kieServices.newReleaseId( "org.acme", "myartifact", "1.0-SNAPSHOT" );
KieContainer kContainer = kieServices.newKieContainer( releaseId );
KieScanner kScanner = kieServices.newKieScanner( kContainer );

// Start the KieScanner polling the Maven repository every 10 seconds
kScanner.start( 10000L );

在此示例中,KieScanner配置为以固定的时间间隔运行,但也可以通过在其上调用scanNow()方法按需运行它。如果KieScanner在Maven存储库中找到该KieContainer使用的Kie项目的更新版本,它会自动下载新版本并触发新项目的增量构建。此时,KieContainer控制下的现有KieBases和KieSessions将自动升级 - 特别是那些使用getKieBase()获得的KieBases及其相关的KieSession,以及直接使用KieContainer.newKieSession()获得的任何KieSession因此引用默认值KieBase。此外,从现在开始,从KieContainer创建的所有新KieBase和KieSession都将使用新的项目版本。请注意,在KieScanner升级之前通过newKieBase()获得的任何现有KieBase及其任何相关的KieSession都不会自动升级;这是因为通过newKieBase()获得的KieBases不受KieContainer的直接控制。

如果使用SNAPSHOT,版本范围,LATEST或RELEASE设置,KieScanner将仅对已部署的jar进行拾取更改。固定版本不会在运行时自动更新。

Maven支持许多机制来管理应用程序中的版本控制和依赖关系。 可以使用特定版本号发布模块,也可以使用SNAPSHOT后缀。 依赖关系可以指定要使用的版本范围,或者采用SNAPSHOT机制的优势。

StackOverflow为此提供了非常好的描述,如下所示。
http://stackoverflow.com/questions/30571/how-do-i-tell-maven-to-use-the-latest-version-of-a-dependency

Runing

从KieContainer 获取 KieBase

KieBase kBase = kContainer.getKieBase();

KieSession

图片.png
KieSession ksession = kbase.newKieSession();

KieRuntime

图片.png

全局Globals与fact不同,他的修改不会触发规则的重新评估。全局变量用户提供静态信息、作为RHS的服务对象,作为规则引擎的返回对象。

事件模型event model

事件提供了通知规则引擎的方法, 包括触发规则、声明对象等。 这运行将日志记录审计与应用程序分离。

KieRuntimeEventManager接口由KieRuntime实现,它提供两个接口,RuleRuntimeEventManager和ProcessEventManager。 我们这里只介绍RuleRuntimeEventManager。


图片.png

RuleRuntimeEventManager 支持监听器的添加和删除,因此working memroy 和 agenda的事件可以被监听 :


图片.png
ksession.addEventListener( new DefaultAgendaEventListener() {
    public void afterMatchFired(AfterMatchFiredEvent event) {
        super.afterMatchFired( event );
        System.out.println( event );
    }
});

Drools提供了DebugRuleRuntimeEventListener and DebugAgendaEventListener , 他们实现了打印语句, 使用如下:

ksession.addEventListener( new DebugRuleRuntimeEventListener() );

所有发出的事件都实现了KieRuntimeEvent接口,该接口可用于检索事件源自的实际KnowlegeRuntime。

图片.png

当前支持的事件由:
The events currently supported are:

MatchCreatedEvent

MatchCancelledEvent

BeforeMatchFiredEvent

AfterMatchFiredEvent

AgendaGroupPushedEvent

AgendaGroupPoppedEvent

ObjectInsertEvent

ObjectDeletedEvent

ObjectUpdatedEvent

ProcessCompletedEvent

ProcessNodeLeftEvent

ProcessNodeTriggeredEvent

ProcessStartEvent

KieRuntimeLogger

图片.png

KieRuntimeLogger使用Drools中的综合事件系统创建审计日志,该日志可用于记录应用程序的执行,以便以后使用Eclipse审计查看器等工具进行检查。

KieRuntimeLogger logger =
  KieServices.Factory.get().getLoggers().newFileLogger(ksession, "logdir/mylogfile");
...
logger.close();

Commands and commandExecutor

KIE拥有有状态或无状态会话的概念。 已经涵盖了使用标准KieRuntime的有状态会话,并且可以随着时间的推移迭代地进行。 Stateless是使用提供的数据集一次性执行KieRuntime。 它可能返回一些结果,会话在最后处理,禁止进一步的迭代交互。

上述的基础是 CommandExecutor 接口, 有状态和无状态接口都会扩展之。


图片.png
图片.png

CommandExecutor允许在这些会话上执行命令,唯一的区别是StatelessKieSession在处理会话之前在结束时执行fireAllRules()。 可以使用CommandExecutor创建命令.Javadocs使用CommandExecutor提供允许的命令的完整列表。

setGlobal和getGlobal是两个与Drools和jBPM相关的命令。

在下面设置全局调用setGlobal。 可选的boolean指示命令是否应该返回全局值作为ExecutionResults的一部分。 如果为true,则它使用与全局名称相同的名称。 如果需要替代名称,可以使用String代替布尔值。

StatelessKieSession ksession = kbase.newStatelessKieSession();
ExecutionResults bresults =
    ksession.execute( CommandFactory.newSetGlobal( "stilton", new Cheese( "stilton" ), true);
Cheese stilton = bresults.getValue( "stilton" );
StatelessKieSession ksession = kbase.newStatelessKieSession();
ExecutionResults bresults =
    ksession.execute( CommandFactory.getGlobal( "stilton" );
Cheese stilton = bresults.getValue( "stilton" );

上述例子都是使用的单条命令。 组合命令使用BatchExecution 。
组合命令是个列表, 他迭代每条命令并执行之。 这意味着可以在一个execute()中insert some objects, start a process, call fireAllRules and execute a query。

StatelessKieSession 会自动在结束时执行fireAllRules() 。

批处理中具有out标识符集的任何命令都会将其结果添加到返回的ExecutionResults实例。 让我们看一个简单的例子来看看它是如何工作的。 出于说明的目的,所呈现的示例包括来自Drools和jBPM的命令。 它们在Drool和jBPM特定部分中有更详细的介绍。

StatelessKieSession ksession = kbase.newStatelessKieSession();

List cmds = new ArrayList();
cmds.add( CommandFactory.newInsertObject( new Cheese( "stilton", 1), "stilton") );
cmds.add( CommandFactory.newStartProcess( "process cheeses" ) );
cmds.add( CommandFactory.newQuery( "cheeses" ) );
ExecutionResults bresults = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
Cheese stilton = ( Cheese ) bresults.getValue( "stilton" );
QueryResults qresults = ( QueryResults ) bresults.getValue( "cheeses" );

你可能感兴趣的:(KIE)