在规则文件中动态地将日历设置为知识会话

时间:2016-11-10 12:41:53

标签: java calendar quartz-scheduler drools

我想在规则文件中将Calendar附加到知识会话中。

目前,我是通过在Java文件中编写所需的代码来实现的:

ClassCalendar.java

package app1;

import org.kie.api.runtime.KieSession;
import org.kie.api.time.Calendar;

import org.quartz.impl.calendar.WeeklyCalendar;

public class ClassCalendar {

  public static final void main(String[] args) {
    try {
      WeeklyCalendar weekDayCal = new WeeklyCalendar();
      weekDayCal.setDaysExcluded(new boolean[] { false, false, false, false, false, false, false, false, false });
      weekDayCal.setDayExcluded(java.util.Calendar.TUESDAY, true);
      Calendar calendar = new CalendarWrapper(weekDayCal);

      String ruleFilePath = "src/main/resources/rules/ruleFile1.drl";
      KieSession kSession = KSessionUtil.buildKSession(ruleFilePath);
      kSession.getCalendars().set("calendar", calendar);

      kSession.insert(new String("hello"));
      kSession.fireAllRules();

      System.out.println("Bye");
    } catch (Throwable t) {
      t.printStackTrace();
    }
  }
}

CalendarWrapper.java

package app1;

import org.kie.api.time.Calendar;
import org.quartz.impl.calendar.WeeklyCalendar;

// A class to act as a converter from Quartz Calendar to Drools Calendar
public class CalendarWrapper implements Calendar {
  private WeeklyCalendar cal;

  public CalendarWrapper(WeeklyCalendar cal) {
    this.cal = cal;
  }

  public boolean isTimeIncluded(long timestamp) {
    return cal.isTimeIncluded(timestamp);
  }

  public static void main(String[] args) {
  }

}

KSessionUtil.java

package app1;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.LinkedList;
import java.util.List;

import org.kie.api.KieBase;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.conf.EqualityBehaviorOption;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.TimedRuleExectionOption;
import org.kie.api.runtime.rule.FactHandle;

public class KSessionUtil {

  public static KieSession buildKSession(String ruleFilePath) {
    List<String> ruleFilePathList = new LinkedList<String>();
    ruleFilePathList.add(ruleFilePath);
    return buildKSession(ruleFilePathList);
  }

  public static KieSession buildKSession(List<String> ruleFilePathList) {
    final boolean showErrors = true;
    final boolean showWarnings = true;
    final boolean showInfo = true;
    final boolean timedRuleOptionEnabled = false;

    KieServices kieServices = KieServices.Factory.get();
    KieFileSystem kfs = kieServices.newKieFileSystem();

    String virtualRuleFilePathFormat = "src/main/resources/ruleFile%d.drl";
    int virtualRuleFilePathIndex = 0;
    for (String ruleFilePath : ruleFilePathList) {
      virtualRuleFilePathIndex++;
      FileInputStream fis = null;
      try {
        fis = new FileInputStream(ruleFilePath);
      } catch (FileNotFoundException e) {
        e.printStackTrace();
        return null;
      }
      String virtualRuleFilePath = String.format(virtualRuleFilePathFormat, virtualRuleFilePathIndex);
      // System.out.println(virtualRuleFilePath);
      kfs = kfs.write(virtualRuleFilePath, kieServices.getResources().newInputStreamResource(fis));
    }

    KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
    Results results = kieBuilder.getResults();
    if (showErrors && results.hasMessages(Message.Level.ERROR)) {
      System.out.println("~~ERROR~~:");
      System.out.println(results.getMessages());
      throw new IllegalStateException("### errors ###");
    }
    if (showWarnings && results.hasMessages(Message.Level.WARNING)) {
      System.out.println("~~WARNING~~:");
      System.out.println(results.getMessages());
    }
    if (showInfo && results.hasMessages(Message.Level.INFO)) {
      System.out.println("~~INFO~~:");
      System.out.println(results.getMessages());
    }

    KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());

    // Change the engine mode to 'stream'
    KieBaseConfiguration config = kieServices.newKieBaseConfiguration();
    config.setOption(EventProcessingOption.STREAM);
    config.setOption(EqualityBehaviorOption.EQUALITY);

    KieBase kieBase = kieContainer.newKieBase(config);

    KieSession kSession = null;
    if (timedRuleOptionEnabled) {
      // Set TimedRuleException to be true
      // It will make fireAllRules() asynchronous ( like fireUntilHalt() )
      // in the case of timed rules.
      KieSessionConfiguration ksconf = KieServices.Factory.get().newKieSessionConfiguration();
      ksconf.setOption(TimedRuleExectionOption.YES);
      kSession = kieBase.newKieSession(ksconf, null);
    } else {
      kSession = kieBase.newKieSession();
    }

    return kSession;
  }

  public static Boolean updateOrInsert(KieSession kSession, Object obj) {
    FactHandle factHandle = kSession.getFactHandle(obj);
    if (factHandle == null) {
      factHandle = kSession.insert(obj);
      return false;
    } else {
      kSession.update(factHandle, obj);
      return true;
    }
  }

  public static void fireAllRules(KieSession kSession) {
    System.out.println("Firing all rules ...");
    kSession.fireAllRules();
    System.out.println("Rules fired!");
  }

}

ruleFile1.drl

package app1;

rule "rule1"
calendars "calendar"
when
    str: String()
then
  System.out.println("In rule - " + drools.getRule().getName());
    System.out.println("String matched " + str);
end

初始化和设置日历所需的代码已写入java文件ClassCalendar.java

WeeklyCalendar weekDayCal = new WeeklyCalendar();
weekDayCal.setDaysExcluded(new boolean[] { false, false, false, false, false, false, false, false, false });
weekDayCal.setDayExcluded(java.util.Calendar.TUESDAY, true);
Calendar calendar = new CalendarWrapper(weekDayCal);

String ruleFilePath = "src/main/resources/rules/ruleFile1.drl";
KieSession kSession = KSessionUtil.buildKSession(ruleFilePath);
kSession.getCalendars().set("calendar", calendar);

有没有办法可以从规则本身做到这一切,所以我可以在java文件中执行此操作:

public static final void main(String[] args) {
  try {
    String ruleFilePath = "src/main/resources/rules/ruleFile1.drl";
    KieSession kSession = KSessionUtil.buildKSession(ruleFilePath);
    kSession.insert(new String("hello"));
    kSession.fireAllRules();

    System.out.println("Bye");
  } catch (Throwable t) {
    t.printStackTrace();
  }
}

2 个答案:

答案 0 :(得分:0)

在Drools中,日历的概念只不过是由日历属性选择为布尔值的时刻图,设置为规则的属性,允许规则触发。 Drools可以根据这样的日历评估当前的日期和时间,并允许或禁止触发规则。但它没有办法改变规则的编译属性。

您可以使用日历事实创建动态逻辑,该日历事实定义可以打开和关闭触发的间隔(&#34;计划&#34;,例如一天中的小时),插入定义计划的事实并使用规则修改这些计划事实。为了评估一组事实,需要根据当前时间评估计划事实,这必须作为另一个事实插入。

rule "determine time to..."
when
    Now( $time: time )
    Schedule( permitsAt( $time ) )
    str: ThisOrThat()
then
    //...

这将需要一定量的工作,但随后动态行为总是更加昂贵......; - )

编辑请注意,可以将一对现在加上一些计划放入单个规则中,该规则可以根据此特定计划应该有效的规则集进行扩展。

答案 1 :(得分:0)

我们可以在规则文件本身中编写日历初始化代码,并在规则的RHS中手动调用isTimeIncluded()方法,以检查规则是否应该在当前时间执行:

package app1;

import java.util.Calendar;
import org.quartz.impl.calendar.WeeklyCalendar;

rule "rule1"
when
    str: String()
then
    System.out.println("In rule - " + drools.getRule().getName());
    WeeklyCalendar weekDayCal = new WeeklyCalendar();
    weekDayCal.setDaysExcluded(new boolean[] { false, false, false, false, false, false, false, false, false });
    weekDayCal.setDayExcluded(java.util.Calendar.TUESDAY, true);
    if ( weekDayCal.isTimeIncluded(System.currentTimeMillis()) )
    {
      System.out.println(str);
      // Other things to do
    }
end