Search code examples
droolsrule

Order of objects retrieved from working memory in Drools


We have been coding a rule that changes the status of billed items that are repeated on the same day and that should only be billed once a day. All items have a status of 2 or 3 to begin with.

If a duplicated code is detected on an item with status 2 or 3, the item will get status 4 and the item in the working memory is updated.

When realising unit testing we can see the results are correct, but once we retrieve the objects from the working memory it seems the order of the items has changed to pretty much random. Is this normal and why does it happen? (Obviously, the anomaly, if any, could be corrected by just reordering the list again).

Objects are inserted this way:

Iterator<Object> it = objects.iterator();
while (it.hasNext()) {
    sessionStatefull.insert(it.next());
}

Its log is achieved by adding a logger to the KieSession:

public static KieSession getStatefulKnowledgeSessionWithCallback(KieContainer kieContainer, String sessionName) {
   KieSession kieSession = null;
    try {
        kieSession = getStatefulKnowledgeSession(kieContainer, sessionName);
        kieSession.addEventListener(new RuleRuntimeEventListener() {
            OutputDisplay outputDisplay = new OutputDisplay();

            @Override
            public void objectInserted(ObjectInsertedEvent objectInsertedEvent) {
                outputDisplay.showText("getStatefulKnowledgeSessionWithCallback.INSERT", objectInsertedEvent.getObject().toString());               
            }

The input is always the same:

Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169800, units=1.0, code=1   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169801, units=1.0, code=1   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169802, units=1.0, code=2   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169803, units=1.0, code=2   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169804, units=1.0, code=6358]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169805, units=1.0, code=6007]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169806, units=1.0, code=6007]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169807, units=1.0, code=6385]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169808, units=1.0, code=6005]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169809, units=1.0, code=6225]

The output is obtained this way:

    List<Object> list = new ArrayList<Object>((Collection<Object>) sessionStatefull.getObjects());

Its log is obtained with an Iterator:

    Iterator<Object> it2 = list.iterator();
    while (it2.hasNext()) {
        Object object = it2.next();
        outputDisplay.showText("Result: ", object.toString());
    }

The printed output always seems to have a random order:

Example 1:

Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169809, units=1.0, code=6225]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=4, id=150107315169801, units=1.0, code=1   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169800, units=1.0, code=1   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=4, id=150107315169803, units=1.0, code=2   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169802, units=1.0, code=2   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169807, units=1.0, code=6385]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169805, units=1.0, code=6007]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169804, units=1.0, code=6358]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=4, id=150107315169806, units=1.0, code=6007]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169808, units=1.0, code=6005]

Example 2:

Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169804, units=1.0, code=6358]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=4, id=150107315169803, units=1.0, code=2   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=4, id=150107315169806, units=1.0, code=6007]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169805, units=1.0, code=6007]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=4, id=150107315169801, units=1.0, code=1   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169808, units=1.0, code=6005]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169807, units=1.0, code=6385]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169800, units=1.0, code=1   ]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169809, units=1.0, code=6225]
Item [date=Tue Jul 25 00:00:00 CEST 2017, status=2, id=150107315169802, units=1.0, code=2   ]

The logger class is defined like this:

public class OutputDisplay {

    public void showText(String source, String text) {
        try {
            long time = System.currentTimeMillis();
            Date date = new Date(time);
            writeLog(time+" "+date.toString()+" A message from "+source+": "+text);

        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

writeLog opens a file and adds the line. We haven't paid any attention yet to some more sophisticated logging (i.e. logback...).


Solution

  • Drools doesn't internally keep the order of the inserted objects. The getObjects() method you are using states this by returning a Collection instead of a List.

    The logger is showing the objects in order because it is invoked as soon as a new object is inserted into the working memory.

    If you want to give some logical order to your objects I would suggest you to order them after you retrieve them from the working memory.

    Hope it helps,