'Is there a way to have a drools variable persist between rules?

What I'm trying to do is concatenate various strings that are individually stored into a global outputMap. However, I have some constraints.

  1. I am not allowed to add any pair into the outputMap that doesn't have a key of "Output".
  2. I am not allowed to insert/set any globals into the kie session aside from the outputMap.
  3. These sub-rules that end in letters below need to be defined as separate rules.

So I tried the following solution with another global variable that isn't being set by a kie session.

import java.util.*

global java.util.Map outputMap;
global java.util.List concatList;

rule 101A
salience 3
when
       $v1:Map()
       $fruit:String() from $v1.get("Strawberries");
then
       outputMap.put("Output", $fruit);
       if(concatList == null)
       {
              concatList = new List<String>();
       }
       concatList.add($fruit);
end

rule 101B
salience 2
when
       $v1:Map()
       $fruit:String() from $v1.get("Cherries");
then
       outputMap.put("Output", $fruit);
       if(concatList == null)
       {
              concatList = new List<String>();
       }
       concatList.add($fruit);
end

rule 101
salience 1
when
       $v1:Map()
       $fruit:String() from $v1.get("All");
then
       String s = "";
       for(int i=0; i<concatList.size(); ++i)
       {
              s+=concatList.get(i);
       }
       outputMap.put("Output", s);
end

The problem with this method is that the global concatList's value seems to reset after every rule execution since I can't insert it into a kie session, and since I have the first constraint, I can't just simply insert it into the output map and retrieve it later.

My question is, is there a way to have a variable persist between rules without it being defined in a kie session?

TLDR: Above question

Thanks



Solution 1:[1]

You can't rely on globals like that.

Generally you'd do this by calling insert, update, and modify to make changes to working memory.

Your example is a little strange (what is this weird map of "Strawberries"->???), but it would generally look something like this:

rule "Init"
when
  not( ArrayList() )
then
  insert( new ArrayList() )
end

rule "Strawberries"
salience 1
when
  $concatList: ArrayList()
  Map( $fruit: this["Strawberries"] )
then
  $concatList.add($fruit)
end

rule "Cherries"
salience 1
when
  $concatList: ArrayList()
  Map( $fruit: this["Cherries"] )
then
  $concatList.add($fruit)
end

rule "Output"
when
  $concatList: ArrayList()
then
  String s = String.join(";", $concatList);
  outputMap.put("Output", s);
end

In the Init rule, I insert an ArrayList into working memory if it doesn't already exist. Then the "Strawberries" and "Cherries" rules add whatever those values from the Map are into that list. And finally the Output rule joins all the values and shoves it into the "outputMap" global.

If you need your rules to be aware of changes to the objects in working memory, you'd call modify or update. Modify will change the object in working memory and reevaluate subsequent rules with the new values. Update is like calling "fire rules" anew with the new values.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Roddy of the Frozen Peas