简体   繁体   中英

Setting and getting a Global variable in Drools

I have something like this in drl file:

import java.lang.String

global String result;

rule ''Rule 1'' when some condition
    then 
result = "PASS";
kcontext.getKnowledgeRuntime().setGlobal("Result", result); // I got an "Unexpected global" exception.
System.out.println("result = "+ Result);

Also, I don't know how to access this global variable from my MyService.java class.

Your rule should not be touching the 'kcontext'. What in the world are you trying to do? result = "PASS" is sufficient for setting the value of the global.

global String result

rule "Rule 1" 
when 
  // some condition
then 
  result = "PASS";
end

Of course it's not going to work like you want it to because you need to change the value of the existing object; you can't overwrite it like that. Some options might be a "ResultsHolder" sort of class with a boolean variable you can set; or maybe even an AtomicBoolean that you can call set on.

To fire rules with a global, you need to add the global objects to the KieBase before invoking your rules:

var value = ...; // some OBJECT which you are going to pass in as a global

KieSession session = ruleBase.newStatefulSession();
session.insert(...); // insert data
session.setGlobal( "myGlobalFoo", value ); // sets the global; note the name must match the rule file!
session.fireAllRules();

After the rules are fired, you'll have your reference to value that you can use. This is also why you can't pass strings as globals and expect them to capture changes -- Java is pass-by-value, not pass-by-reference.


Here's an example for passing results out of the rules. This toy app will check the student's score on a test and then decide if they passed or failed.

Classes:

class Student {
  private String name;
  public String getName() { return this.name; }
  public void setName(String name) { this.name = name; }
}

class Exam {
  private String name;
  private Double score;
  public String getName() { return this.name; }
  public void setName(String name) { this.name = name; }
  public Double getScore() { return this.score; }
  public void setScore(String score) { this.score = score; }
}

class ExamResults {
  private List<String> results = new ArrayList<>();
  public void logResults( String name, Double score, boolean passed ) {
    this.results.add(name + " scored " + score + "%, which is a " + (passed ? "passing": "failing") + " grade.");
  }
  public List<String> getResults() { return this.results; }
}

Rule:

global ExamResults results;

rule "Evaluate exam"
when
  Student( $name: name )
  Exam ( $score: score, name == $name )
then
  boolean passed = $score > 60.0;
  results.logResults( $name, $score, passed );
end

Invocation:

List<Student> students = ...;
List<Exam> exams = ... ;
ExamResults results = new ExamResults();

KieSession session = ruleBase.newStatefulSession();
students.forEach( student -> session.insert(students) );
exams.forEach( exam -> session.insert(exam) );
session.setGlobal( "results", results);
session.fireAllRules();

// Print the results:
results.getResults().forEach(System.out::println);

If all you're trying to do is to get some data out of your rules (eg whether certain conditions match), I've written up answers about how to do that previously here and here . If you just want to know what rules triggered, you should write a listener which logs rule hits ("afterMatchFired").

I was trying to set a global variable from the drl file not my java class like Service class.

All I had to do was the following and it worked successfully

import java.lang.String

global String result;

rule ''Rule 1'' when
some condition

then

String grade = "PASS";

kcontext.getKnowledgeRuntime().setGlobal("result", grade);  
                                                                                                                

end

Also, the global variable name should match what I pass on the setGlobal("result",...).

And then get the global variable using the session I have in the Service class. like:

session.getGlobal("result");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM